跨域多方位解決方案

本次分享由趣頭條cpc商業化技術部(周志祥-混元霹靂手)進行分享!歡迎你們投遞簡歷加入趣頭條,郵箱地址爲qianjiongli@qutoutiao.net 期待您的加入。html

你瞭解跨域嗎?

瞭解(continue) 不瞭解 (end)前端

爲什麼會產生跨域?

跨域問題來源於瀏覽器同源策略的限制問題致使的。vue

瀏覽器爲什麼要設置同源策略?

正是由於瀏覽器要出於安全考慮。若是缺乏了同源策略,瀏覽器很容易受到XSSCSRF等攻擊。(XSSCSRF能夠單獨成爲一個額外的知識點) 此時會致使一個域名下網頁的操做就能夠直接拿到另外一個非同域名下網頁的任何信息,或者一個網頁能夠隨意請求到不一樣域名服務器下的接口數據。node

什麼是同源策略?

同源策略是一種約定,這是瀏覽器核心的安全功能點之一。所謂的同源策略指的是【協議 + 域名 + 端口】三者相同,若是兩個相同的域名指向同一個ip地址,也是非同源的狀況。同時地址印射對應的ip二者也是非同源狀況。web

同源策略會存在那些限制?

DOM節點ajax

對於DOM節點只能操做當前域名下網頁打開的DOM節點內容。chrome

存儲信息vue-cli

對於cookiesessionStoragelocalStorageindexedDB等存儲信息也不能非同源獲取express

ajax請求json

對於ajax網絡請求時,請求處於非同域的狀況下會被瀏覽器自動攔截報錯。

舉幾個形成跨域的場景的例子?

前面說過當協議、域名、端口號中任意一個不相同時,都是跨域。一樣包括(一級域名與二級域名的不一樣) 互相請求資源的狀況下是一種跨域狀態。

跨域的地址場景圖

經過什麼方式能夠解決跨域?

能夠經過JSONP的原理

首先明白對於瀏覽器加載資源時能夠經過:

  1. img
  2. script
  3. link

以上幾個標籤是容許跨域加載資源的。意思就是在www.baidu.com域名下靜態html文件中的script標籤能夠加載wwww.google.com服務器下的腳本資源等。

經過以上標籤能夠加載跨域資源的理解,那咱們能夠經過包裝手段從其它域獲取到指望的數據。

講講JSONP的實現原理?

以前已經有了原理的思路的鋪墊。那就利用script標籤這一容許跨域加資源的特性包裝數據進行講解。

實現流程

// index.html
// jsonp的實現模擬
function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script')
    window[callback] = function(data) {
      resolve(data)
      document.body.removeChild(script)
    }
    params = { ...params, callback }
    let arrs = []
    for (let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    script.src = `${url}?${arrs.join('&')}`
    document.body.appendChild(script)
  })
}

// 調用方式
jsonp({
  url: 'http://localhost:3000/getUser',
  params: { name: 'peter' },
  callback: 'user'
}).then(data => {
  console.log(data)
})
複製代碼

經過以上代碼實現了一個基本的JSONP的調用執行代碼。

  1. 聲明一個JSONP的模擬函數, 傳入的參數分別爲請求地址請求參數先後端約定的包裝函數名、 內部經過返回promise機制來優雅的解決數據返回的獲取方式。

  2. 經過script不存在跨域請求資源的機制建立一個script臨時標籤。把向後臺請求的地址和參數組合成query參數的形式。 請求地址: http://localhost:3000/getUser?name=peter&callback=user

關健點是把包裝的函數名(key做爲callback, value做爲user) 包裝函數名是先後端一個約定。

  1. 最後組裝後的script標籤插入到document文檔中,此時瀏覽器就會自動向標地址發起請求。

後臺返回的結果原理

// app.js 用express腳手架模擬的配合前臺callback封裝的返回結果

app.get('/getUser', function(req, res, next) {
  let { name, callback } = req.query
  console.log(name) // peter
  console.log(callback) // user
  res.send(`${callback}({
    code: 0,
    msg: '請求成功',
    data: {
      id: 1234
    }
  })`)
});
複製代碼

後臺會經過query參數進行解析。若是此時返回的結果是一個對象,對象中存在msg消息,請求狀態碼code,數據信息data

可能你會疑問爲何返回的結果的值是放在一個user執行函數中。這就是JSONP的核心原理。回頭再看看這段沒有解釋的代碼段:

window[callback] = function(data) {
  resolve(data)
  document.body.removeChild(script)
}
複製代碼

當執行本身封裝的jsonp的方法的時候在全局定義一個函數。此函數名則是前端與後端約定的函數封裝名。當後臺返回結果時會執行約定好的全局函數。就是執行上方代碼段, 數據參數會經過resolve執行返回。最後刪除對應的請求script標籤。

JSONP和AJAX對比,區別點在那裏?

相同點:

JSONPajax二者相同點都是客戶端向服務端發起請求。

不一樣點:

JSONP屬於利用script標籤進行了非同源策略請求,而ajax是同源策略請求。

JSONP優缺點

優勢:

JSONP的優勢是兼容性很好。由於利用的是script標籤能夠非同源請求機制。這是每一個瀏覽器基礎特性。

缺點:

只支持query參數的這種get請求方式,交互方式存在侷限性。也容易受到xss的攻擊。

若是後臺不支持JSONP的封裝方式怎麼辦?

能夠經過CORS網絡通訊技術。(全稱Cross-Orgin Resource Sharing),對於CORS一樣也須要先後端進行一個配合。可是關健點在於後臺的配置。可能你會認爲。即然是後臺進行配置,爲何前臺也須要充分的瞭解。由於不管在生產仍是開發的模式下, 跨域首先對前端的影響面是最大的, 只有充分的瞭解才能向後臺去表達後臺才能準確的設置和進行配合。

簡單的跨域請求須要建議後臺進行什麼設置?

前臺模擬設置

先本地建立一個index.html寫入請求腳本。經過http-server -p 4000啓動在本地4000端口下。

// index.html
let url = 'http://localhost:3000/getUser';
let xhr = new XMLHttpRequest();
xhr.open('get', url, true);
xhr.send();
複製代碼

後臺模擬設置

經過express框架設置請求地址,服務啓動在本地3000端口下。

// app.js
let express = require('express')
let app = express()

app.get('/getUser', function(req, res) {
  res.send({
    code: 0,
    msg: '請求成功',
    data: {
      id: 1234
    }
  })
})

app.listen(3000)
複製代碼

瀏覽器返回結果

訪問http://127.0.0.1:4000/index.html能夠經過Network控制檯能夠看到瀏覽器端向後臺http://localhost:3000/getUser服務接口地址發出請求。

若是Origin指定的源,不在許可範圍內,服務器會返回一個正常的HTTP迴應。瀏覽器發現,這個迴應的頭信息沒有包含Access-Control-Allow-Origin字段,就知道出錯了,從而拋出一個錯誤,被XMLHttpRequestonerror回調函數捕獲。注意,這種錯誤沒法經過狀態碼識別,由於HTTP迴應的狀態碼有多是200。雖然返回的 Status Code 狀態碼是 200 OK,可是response響應頭裏並無返回指望的值。一樣在console控制檯能夠發現:

Access to XMLHttpRequest at 'http://localhost:3000/getUser' from origin 'http://127.0.0.1:4000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
複製代碼

CORS策略阻止了從http://127.0.0.1:4000訪問http://localhost:3000/getuser處的XMLHttpRequest:請求的資源上沒有'Access- control - allow-origin'頭。

這就是一個最簡單的CORS的安全策略,從報錯能夠很明顯的明白你須要告訴後臺須要設置'Access- control-allow-origin'頭。

後臺解決方案

// app.js中添加

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*')
  // res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
  next()
})

複製代碼

在接收到請求時作一層中間件的過濾, 如下二者方式皆可。

  1. 返回時設置響應頭的Access-Control-Allow-Origin*(表明全部域名向當前服務請求都容許跨域訪問)
  2. 返回時設置響應頭的Access-Control-Allow-Origin爲指定的域名。其它域名都不容許進行一個跨域訪問

設置Access-Control-Allow-Origin頭就能夠解決了全部的跨域問題了麻?

Access-Control-Allow-Origin頭的設置僅僅只能解決簡單的跨域請求

簡單的跨域請求條件:

條件1: 只能容許如下的請求方法

  • GET
  • HEAD
  • POST

條件2: Content-Type容許條件

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

條件3: 不能超過http的頭信息如下字段

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID

那其它請求方式如何解決?屬於什麼類型的跨域請求?

其它的請求方式被稱之爲複雜的跨域請求。一旦不符合簡單跨域請求策略的時候那就是複雜的跨域請求:

複雜的跨域請求解釋:

  1. 除了簡單的跨域請求的方法。好比PUTDELETE
  2. 除了簡單的跨域請求的Content-type類型。好比application/json
  3. 自定義的header
  4. 不一樣域名下的cookie傳輸

嘗試解決複雜跨域的幾種狀況

1.put、delete等請求方法形成複雜請求

// 修改請求方法
- xhr.open('get', url, true);
+ xhr.open('put', url, true);
複製代碼
// 修改後臺接收請求方法
app.put('/getUser') // 省略... 對於後臺只是把get請求換成put接收請求
複製代碼

在瀏覽器的netWork中發現並無發送put請求,在General中的Request Method發現發送了一個OPIONS的預檢請求(關於預檢後續會在解決跨域問題中經過關閉瀏覽器策略中專門介紹相關詳細知識點)

同時瀏覽器中會被髮出報錯信息:

Access to XMLHttpRequest at 'http://localhost:3000/getUser' from origin 'http://127.0.0.1:4000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 複製代碼

解決方案:

// 在app.use中添加新的設置頭
// res.setHeader('Access-Control-Allow-Methods', '*')
res.setHeader('Access-Control-Allow-Methods', 'PUT')
複製代碼

以上設置了接收容許那些請求方法:

  • 設置*, 表示全部請求方法都容許。
  • 設置對應的請求方法以逗號分隔。

2.content-type形成複雜請求

+ xhr.setRequestHeader('content-type', 'application/json');
複製代碼

在以前談論簡單跨域請求條件二, 關於content-type類型對於簡單的跨域請求只支持三種。設置其它的則會產生複雜的跨域請求。當設置content-type: application/json的狀況下,一樣的瀏覽器會發出報錯信息:

Access to XMLHttpRequest at 'http://localhost:3000/getUser' from origin 'http://127.0.0.1:4000' has been blocked by CORS policy: Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
複製代碼

從報錯提示能夠看出後臺須要對複雜跨域請求content-type進行一個額外的設置:

// 在app.use中添加新的設置頭
+ res.setHeader('Access-Control-Allow-Headers', 'content-type')
複製代碼

3.自定義頭形成複雜請求

+ xhr.setRequestHeader('X-Customer-Header', 'value');
複製代碼

在以前談論簡單跨域請求條件三中, 除了以上幾種http請求頭以後,都屬於自定義頭。在請求帶入時會形成複雜的跨域請求, 一樣的瀏覽器會發出報錯信息。

Access to XMLHttpRequest at 'http://localhost:3000/getUser' from origin 'http://127.0.0.1:4000' has been blocked by CORS policy: Request header field x-customer-header is not allowed by Access-Control-Allow-Headers in preflight response.
複製代碼

一樣的原理對於前臺設置的自定義頭後,後臺在接收的時候一樣也要進行容許設置接收前臺自定義傳輸出來的自定義頭。

res.setHeader('Access-Control-Allow-Headers', 'content-type, X-Customer-Header')
// res.setHeader('Access-Control-Allow-Headers', '*')
複製代碼

Access-Control-Allow-Headers設置的時候,能夠用逗號分隔,進行多個自定義頭的設定。同時也能夠傳入*,容許所任何自定義頭。

談談CROS中的cookie?

絕對同域的狀況下

在絕對同域的狀況下。前臺向後臺請求的接口或者請求文件的時候,會自動把cookie帶入請求頭中。

在非同域的狀況下

在非同域的狀況下。須要使用CORS的策略進行傳輸。默認狀況下,cookie並不會帶入請求頭中,須要對xhr設置請求憑證。

xhr.withCredentials = true
複製代碼

簡單的跨域請求與cookie

若是此時是簡單的跨域請求, 設置withCredentials = true的狀況下。請求頭中會帶入cookie信息, 後臺接收請求而且會發送到前臺, 此時瀏覽器端從response中能夠看到數據已經返回,可是並不能獲取的後臺返回的數據, 由於此時會被xhr的錯誤進行捕獲,瀏覽器控制檯會出現如下提示:

Access to XMLHttpRequest at 'http://localhost:3000/getUser' from origin 'http://localhost:4000' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute. 複製代碼

複雜的跨域請求

若是此時是複雜的跨域請求,設置withCredentials = true的狀況下。此時會發送一個OPTIONS請求。瀏覽器發出的錯誤信息仍然是與簡單的跨域請求報錯一致。

解決方案

此時前臺發送cookie憑證, 一樣的後臺同樣須要贊成接收憑證。

res.setHeader('Access-Control-Allow-Credentials', true)
複製代碼

反向原理:

若是後臺贊成接收憑證。而前臺沒有設置發送憑證的狀況下。就算後臺發送到前臺的響應頭中設置了cookie信息(set-cookie頭),不管是簡單的跨域請求仍是複雜的跨域請求都會致使cookie塞入無效,能夠查看appliation/cookie中, 不會有後臺寫入的cookie信息。

保持同源策略

爲了安全問題。cookie本質上仍是保持了同源策略的模式。在先後臺都設置了發送/接收憑證以後, 對於反回的origin頭的設置res.setHeader('Access-Control-Allow-Origin', '*') 不能爲*, 須要設置成指定請求的來源 res.setHeader('Access-Control-Allow-Origin', req.headers.origin)

合法組合與非法組合。

當設置Credentials的時候,後臺須要知道Access-Control-Allow的合法與非法組合性。 一旦Access-Control-Allow-Credentials設置爲true的時候, 此時如下幾個不能設置爲*, 須要進行指定, 不然如下三者一率視爲無效設置。

  • Access-Control-Allow-Headers
  • Access-Control-Allow-Origin
  • Access-Control-Allow-Methods

CORS狀況下如何在xhr中拿到響應頭中的信息?

能夠經過xhr.getResponseHeader方法進行獲取。可是此方法只能拿到6個基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma

在後臺響應的時候能夠響應頭中塞入一些自定義的頭和值。

res.setHeader('name', 'peter')
複製代碼

在響應體的報文中能夠看到:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type, X-Customer-Header
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Origin: http://localhost:4000
Connection: keep-alive
Content-Length: 50
Content-Type: application/json; charset=utf-8
Date: Sun, 17 Feb 2019 08:18:08 GMT
ETag: W/"32-oUKytSTXnBL0hnySFj9PpHgmBQk"
name: peter   // 重點在這裏
X-Powered-By: Express
複製代碼

經過報文能夠發現返回的不少以前後臺設置的信息和這裏最關健的name頭信息。可是經過如下方法測試以後結論:

xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      console.log(xhr.getResponseHeader('Content-Type'))
      console.log(xhr.getResponseHeader('name'))
    }
  }
}
複製代碼

xhr返回成功以後。分別獲取兩個頭信息。

  • Content-Type 則會返回 application/json; charset=utf-8

  • name 則會提示報錯信息,而且返回null空值。

Refused to get unsafe header "name" // 拒絕獲取不安全的頭信息「name」
複製代碼

能夠明確的知識,除了以前提到的以上六種頭信息能夠進行獲取以外,其他的一概都須要在後臺進行容許那響應些頭訪問的設置。

res.setHeader('Access-Control-Expose-Headers', 'name')
複製代碼

此時瀏覽器中報錯信息不會存在,同時也能打印出name在響應頭中的值。注意 若是設置的值爲 * 則無效。須要對指定字段頭進行設置。

複雜的跨域請求會形成每次請求都發送一個OPTIONS請求,如何解決?

經過以上的全部對複雜的跨域請求的分析清楚的認識到,那些請求方式會形成發送預檢,一句話歸納,**Access-Control-Max-Age 這個響應首部表示 preflight request (預檢請求)的返回結果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 能夠被緩存多久。**這樣對network中的請求觀察和請求性能來講都不友好。若是作到友好又安全的機制。

對預檢進行一個時間請求有效期

res.setHeader('Access-Control-Max-Age', 600)
複製代碼

對預檢請求設置10分鐘的過時時間(時間能夠根據項目狀況進行自定義)。可是對於每一個瀏覽器的緩存時間機制都不同。在本地調試的時候,有時候你會發現設置了預檢的過時時間並不生效。注意一下可能開啓了瀏覽器的Disable cache致使了此緣由

在先後端聯調時,不經過後端設置,如何解決跨域問題?

關閉瀏覽器跨域策略。

經過以前分析整個跨域模式是由前臺瀏覽器的所做所爲形成的。爲了安全,瀏覽器對跨域請求作了一系列的驗證。那是否能夠想一想, 經過手動關閉瀏覽器跨域策略是否是能夠解決根本性的問題。

Mac 建立一個chrome.sh文件

#!/bin/bash
#!/bin/sh 
open -a "Google Chrome" --args --disable-web-security  --user-data-dir

exit 0
複製代碼

經過終端運行:

sh 加上chrome.sh文件地址
複製代碼

注意: 在運行終端命令的時候,先檢查是否已經啓動過chrome,若是啓動過須要手動關閉整個chrome的進程。

成功結果:

輸入URL地址以後。全部的跨域問題會一併解決。

原理

雖然瀏覽器的跨域策略已經被關閉了。不存在任何瀏覽發送的跨域行爲, 其內部原理正是由於瀏覽器會對簡單的跨域請求作了攔截和複雜的跨域請求作了發送預檢。

簡單的跨域請求經過什麼進行攔截?

在理解簡單的跨域請求時先須要理解兩個請求頭的字段。

request請求頭中的Origin

請求首部字段 Origin 指示了請求來自於哪一個站點。該字段僅指示服務器名稱,並不包含任何路徑信息。該首部用於 CORS 請求。

通俗的說就是告訴服務器此時是從那個域名地址發送來的。只有在CORS的狀況下Origin纔會在請求頭中出現。

request請求頭中的HOST

Host 請求頭指明瞭服務器的域名(對於虛擬主機來講),以及(可選的)服務器監聽的TCP端口號。 若是沒有給定端口號,會自動使用被請求服務的默認端口(好比請求一個HTTPURL會自動使用80端口)。 HTTP/1.1 的全部請求報文中必須包含一個Host頭字段。若是一個 HTTP/1.1 請求缺乏Host 頭字段或者設置了超過一個的 Host 頭字段,一個400(Bad Request)狀態碼會被返回。

通俗的說就是瀏覽器向服務端發送請求時, 所請求的服務器的域名地址。

響應頭中的Access-Control-Allow-Origin

響應頭指定了該響應的資源是否被容許與前臺請求頭給定的origin共享。

結論

因此跨域請求返回瀏覽器以後。雖然數據會返回可是。瀏覽器會比對請求頭中的Origin與響應頭中的Access-Control-Allow-Origin是不是共享匹配,若是不匹配。瀏覽器的xhr會捕獲錯誤而且在瀏覽器端控制檯拋出錯誤。並不能拿到指望的數據。

複雜的請求瀏覽器是如何檢測跨域的?

對於複雜的請求跨域, 瀏覽器一旦檢測此發送的請求頭存在屬於複雜的跨域請求時, 首先會發送一個預請求, 請求頭中包函着如下重要的內容:

  1. Access-Control-Request-Headers(若是有自定義頭或者content-type類形不屬於簡單請求的類型的狀況下才會出來)
  2. Access-Control-Request-Method(除了簡單的請求方法纔會出現)

而且在發送預檢請求時並不會把請求數據和cookie信息帶入請求信息中。

什麼是預檢請求?

CORS中會使用 OPTIONS 方法發起一個預檢請求(preflight request), 以獲知服務器是否容許該實際請求。"預檢請求「的使用,能夠避免跨域請求對服務器的用戶數據產生未預期的影響。

當瀏覽器請求頭中發出request-Header或者request-Method時。此時服務端須要贊成這兩個請求頭中對應的信息經過容許。須要在響應返回的時候對響應頭作出響應處理。須要對Access-Control-Allow-MethodsAccess-Control-Allow-Headers設置。

原理圖:

附帶Credentials(身份憑證的)請求屬於簡單的跨域請求仍是複雜的跨域請求?

關於CredentialsCORS中原理性已經講的很明白了。可是這裏想講的就是在xhrCredentials設置爲true時。此時只是簡單的跨域請求,不會發送預檢(OPTIONS)請求, 若是此時是複雜的跨域請求。會發送預檢(OPTIONS)請求。

因此Credentials是否會發送預檢,主要須要經過其它請求頭的斷定來決定是否須要發送預檢。

原理圖:

總結:

只有當request請求頭與response返回頭一一對應上了。互相容許經過共享策略。對於簡單的跨域請求則不會被捕獲錯誤.對於複雜的跨域請求則會發送真正的請求。同時會把cookie等傳輸數據帶入請求體中。因此說關閉瀏覽器跨域策略就是關閉了瀏覽器對響應Origin頭匹配時再也不捕獲,同時也會關閉對應的OPTIONS預檢請求。直接發送給對應的後臺服務器。因此說本質上雖然存在跨域,可是服務端永遠是返回數據。一切的錯誤或者沒有發送真正的請求都是瀏覽器的安全機制所爲。

如何經過代理劫持機制解決跨域?

前面咱們已經知道瀏覽器向服務器請求是存在跨域問題,可是服務器向服務器發送請求是不存在跨域問題。經過MS(middle server)進行請求劫持以後,經過服務端向服務端發送請求,再二次返回給瀏覽器端。

示意圖:

在各大框架中都經過腳手架啓動node服務承載着項目。例如vue-cli中就利用了http-proxy-middle進行一個請求的代理攔截,向目標服務器發送請求來解決跨域問題。

// 經過express啓用3000端口

// index.html
<script>
  let url = '/api/getUser';
  let xhr = new XMLHttpRequest();
  xhr.open('post', url, true);
  xhr.setRequestHeader('content-type', 'application/json');
  xhr.setRequestHeader('X-Customer-Header', 'value');
  xhr.send();
  xhr.onreadystatechange = function() {
    if (xhr.readyState === 4) {
      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
        console.log(1)
        console.log(xhr.response)
      }
    }
  }
  
</script>


const proxyOption = {
	target: 'http://localhost:4000',
	pathRewrite: {
        '^/api/' : '/'  // 重寫請求,api/解析爲/
    },
    changeOrigin:true
};

app.use('/api', proxy(proxyOption))

複製代碼
// 後臺服務啓動4000端口
app.post('/getUser', (req, res, next) => {
  res.send({
    code: 1
  })
})
複製代碼

3000端口的靜態文件發送ajax請求的時候,自己就是在一個域名下,不會形成任何跨域問題,同時會被app.use('/api/')捕獲攔截,同時改寫url地址向服務端4000端進行請求發送數據。此時就是server端與server端的請求通訊。當4000端口的server接收到請求以後把數據返回給3000端口的server端,同時再返回給請求的ajax

用node原生API如何實現?

app.use('/api', (req, res) => {
  const reqHttp = http.request({
    host: '127.0.0.1',
    path: '/getUser',
    port: '4000',
    method: req.method,
    headers: req.headers
  }, (resHttp) => {
    let body = ''
    resHttp.on('data', (chunk) => {
      console.log(chunk.toString())
      body += chunk
    });
    resHttp.on('end', () => {
      res.end(body)
    });
  })
  reqHttp.end()
});
複製代碼

以上代碼本質上是模擬了代理劫持的方式,同時當攔截到url開頭以/api起始的請求以後,經過node原生http模塊的request方法向對應的後臺發送請求,同時把瀏覽器請求過來的一些請求體,請求頭等數據一併傳給server端。經過http模塊監聽的結束方法最後把數據再返回到client瀏覽器端。這樣造成了二次轉方式解決跨域問題。總體就是利用了服務端向服務發送請求不會有跨域策略的限制,就是所謂的同源策略。由於瀏覽器會作options等預檢的檢測,而服務端並不會。

相關文章
相關標籤/搜索