基於Chrome插件實現支持CORS的本地開發代理

什麼是跨域

跨域:因爲瀏覽器的同源策略,屬於不一樣域的頁面之間不能相互訪問各自的頁面內容。web

開發中後臺項目,咱們首先須要讓本地服務run起來,起一個如http://localhost:8000/scg/show這樣的頁面,而後,當咱們須要進行網絡交互時,一般使用相對域名,如/scg/search.json?pageNo=1, 假設項目的代理配置以下chrome

undefined

那麼當請求/scg/search.json?pageNo=1時,代理轉發出去的請求的是http://ottscg.alibaba.net/scg/search.json?pageNo=1, localhost去請求ottscg.alibaba.net中的內容,這時就發生了跨域。json

CORS跨域發送 Cookie

瀏覽器經過代理髮出CORS請求時,會在頭信息之中,增長一個Origin字段,表示本次請求來自哪一個源(協議 + 域名 + 端口)。服務器根據這個值,決定是否贊成此次請求。若是Origin指定的源,不在許可範圍內,服務器會返回一個正常的HTTP迴應。瀏覽器發現,這個迴應的頭信息沒有包含Access-Control-Allow-Origin字段,就知道出錯了,從而拋出一個錯誤,被XMLHttpRequest的onerror回調函數捕獲。跨域

若是Origin指定的域名在許可範圍內,服務器返回的響應,會多出幾個以"Access-Control"開頭的頭信息字段,爲了發送帶cookie的跨域請求,咱們首先須要關心的是Access-Control-Allow-OriginAccess-Control-Allow-Credentials瀏覽器

Access-Control-Allow-Origin

這個頭是容許CORS時,必須返回的頭,它的值要麼是請求時Origin字段的值,要麼是一個*,表示接受任意域名的請求。bash

Access-Control-Allow-Credentials

默認狀況下瀏覽器對跨域請求不會攜帶 Cookie,但鑑於 Cookie 在身份驗證等方面的重要性, CORS 推薦使用額外的響應頭字段來容許跨域發送 Cookie。 這是一個可選的頭,若發送帶cookie的請求,則必須返回這個頭,並設置爲true,表示服務器容許客戶端發送Cookie。   須要注意的是,這個頭被設置爲true時,Access-Control-Allow-Origin不容許使用*,並且只能指定單一域名,不然瀏覽器會報以下錯誤。服務器

undefined

綜上, 發送cookie的CORS的正確姿式是:cookie

  • 客戶端爲fetch配置 credentials 項:credentials: 'include';
  • 服務端返回的responseHeader中攜帶以下兩個頭信息字段
    Access-Control-Allow-Origin: Origin;
    Access-Control-Allow-Credentials : true
    複製代碼

The include part tells Chrome that you want to send a CORS request to the server which sends along the cookies properly網絡

Chrome插件裏怎麼作

經過了解CORS原理,咱們知道了不支持CORS的服務端會返回一個正常的HTTP迴應,只是因爲沒有Aceess-control相關的響應頭,致使瀏覽器對響應進行了攔截。利用chrome.webRequest API,對onHeadersReceived進行監聽,便可在每次接收到 HTTP(S) 響應標頭時,添加須要的header字段,讓瀏覽器覺得這些頭信息是服務端返回的,從而繞過CORS限制。app

//Breaking the CORS Limitation
chrome.webRequest.onHeadersReceived.addListener(details=>window.onHeadersReceivedCallback(details), {
  urls: ['<all_urls>']
}, ["blocking", "responseHeaders"]);
複製代碼

簡單請求和複雜請求

只設置Access-Control-Allow-Origin和Access-Control-Allow-Crendentials兩個字段,並不能知足全部的場景。例如,咱們在使用Antd的Upload組件進行上傳圖片時,Chrome會報以下錯誤:

undefined

Preflight

Access-Control-Allow-Origin響應頭字段能夠容許跨域 AJAX, 但對於非簡單請求,CORS 機制跨域會首先進行 preflight(一個 OPTIONS 請求,表示這個請求是用來詢問的)

undefined

簡單請求

具體是指請求方法是簡單方法且請求頭是簡單頭的 HTTP 請求。具體地,

  • 簡單方法包括GET, HEAD, POST。
  • 簡單頭包括:Accept, Accept-Language, Content-Language,以及值爲application/x-www-form-urlencoded, multipart/form-data, text/plain 其中之一的 Content-Type 頭。 對於非簡單請求瀏覽器會首先發送 OPTIONS 請求(成爲 preflight)

Access-Control-Request-Headers

Access-Control-Request-Headers 是 preflight 請求中用來標識真正請求將會包含哪些頭部字段, 例以下述請求中Access-Control-Request-Headers字段的值是x-requested-with,告知服務器,實際請求將攜帶這個自定義請求首部字段。服務器據此決定,該實際請求是否被容許,若是容許,服務器應當在對應的Access-Control-Allow-Headers響應頭中包含這個字段。 不然即便返回 200 preflight 也會失敗。

undefined

查看Antd Upload組件的源碼,咱們看到,在上傳圖片時,增長了x-requested-with請求頭,由此觸發了非簡單請求,會在CORS時先進行Option詢問

undefined

綜上,爲了處理非簡單請求下的CORS,除了Access-Control-Allow-Origin和Access-Control-Allow-Crendentials外,咱們還須要在Header劫持中添加以下配置

Access-Control-Allow-Methods:"*",
Access-Control-Allow-Headers:"Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With"
複製代碼
相關文章
相關標籤/搜索