CORS 解決跨域問題

瀏覽器的同源安全策略

是由 NetScape 提出的著名的安全策略,全部支持 javaScript 的瀏覽器都使用這個策略。同源策略限制了一個源中加載文本或腳本與來自其它源中資源的交互方式,同源策略是瀏覽器最核心也最基本的安全功能。html

怎樣算跨域呢?前端

  1. 請求協議 http ,  https 的不一樣
  2. 域 domain 的不一樣
  3. 端口 port 的不一樣(IE 未將端口號加入到同源策略的組成部分之中)

瀏覽器只容許請求當前域的資源,而對其餘域的資源表示不信任。可是現代瀏覽器在安全性和實用性上作出了讓步, img/script/style/iframe 等有 src 屬性的都容許跨域引用資源。java

CORS

這是一個 W3C 標準,全稱是「跨域資源共享」(Cross-Origin Resource Sharing),它容許瀏覽器向跨域服務器發出 XMLHttpRequest 請求,從而解決了 Ajax 只能同源使用的限制。 CORS 須要瀏覽器和服務器同時支持,可是整個通訊過程,都是瀏覽器自動完成(IE瀏覽器不能低於IE10)。json

簡單請求

  • 請求方式只能是: head ,  post ,  get 
  • 請求頭容許的字段: Accept , Accept-Language , Content-Language , Last-Event-ID 
  • Content-Type: application/x-www-form-urlencoded 、 multipart/form-data 、 text/plain 三選一

對於簡單請求,瀏覽器直接發出 CORS 請求。瀏覽器會自動在頭信息(Request Headers)中,添加一個 Origin 字段,來代表本次請求來自哪一個域(Chrome 在非跨域的狀況下,也會發送 Origin 字段)。跨域

若是這個源不在許可範圍內,服務器會返回一個正常的 HTTP 迴應。瀏覽器發現,這個迴應的頭信息沒有包含 Access-Control-Allow-Origin 字段,就知道出錯了,從而拋出一個錯誤,被 XMLHttpRequest 的 onerror 回調函數捕獲。注意,這種錯誤沒法經過狀態碼識別,由於 HTTP 迴應的狀態碼有多是200。瀏覽器

PHP 服務端配置示例:緩存

header('Access-Control-Allow-Origin:http://127.0.0.1:80');

設置爲 * 表示該數據對任何人可見(可是瀏覽器將不會發送 Cookie ,即便 xhr 設置了 withCredentials ),若是隻但願特定的地址訪問,能夠設置爲對應的地址。安全

附帶身份憑證的跨域請求

通常基於 HTTP Cookie 的驗證身份對於跨域 XMLHttpRequest 請求來講,瀏覽器並不會發送對應的身份憑證信息,若是須要帶上身份憑證的 XMLHttpRequest 請求,須要作額外的設置。服務器

PHP 服務端示例:cookie

header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Origin:{$_SERVER['HTTP_ORIGIN']}");  // 動態獲取請求域。能夠先設置一個白名單列表,判斷Orign是否在白名單裏

前端 Ajax 也要打開 withCredentials 屬性,從而向服務器發送 Cookie ,服務端設置 Access-Control-Allow-Credentials:true 來把響應內容返回請求者:

// Jq
xhrFields: { withCredentials: true }
// 原生
var xhr=new XMLHttpRequest();
xhr.withCredentials=true;

對於附帶身份憑證的請求,服務器不得設置 Access-Control-Allow-Origin 的值爲 * 。這是由於請求的首部中攜帶了 Cookie 信息,若是 Access-Control-Allow-Origin 的值爲 * ,請求將會失敗。

也就是說 Access-Control-Allow-Credentials 設置爲 true 的狀況下, Access-Control-Allow-Origin 不能設置爲 * 。

Cookie 依然遵循同源政策,只有用服務器域名設置的 Cookie 纔會上傳,其餘域名的 Cookie 並不會上傳,且(跨源)原網頁代碼中的 document.cookie 也沒法讀取服務器域名下的 Cookie 。

非簡單請求

除了上面說的簡單請求外都是非簡單請求。如:請求方法是 PUT 或 DELETE ;或者 Content-Type 字段的類型是 application/json ;又或者有自定義請求頭。

瀏覽器會先發送 option (預檢)請求,要求服務器確承認以這樣請求。服務端須要加兩個參數設置:

//指定容許其餘域名訪問
header('Access-Control-Allow-Origin:$_SERVER['HTTP_ORIGIN']')
//是否容許後續請求攜帶認證信息(cookies),該值只能是true,不然不返回
header('Access-Control-Allow-Credentials:true')
//預檢結果緩存時間
header('Access-Control-Max-Age: 1800')
//容許的請求類型
header('Access-Control-Allow-Methods:GET,POST,PUT,POST')
//容許的請求頭字段
header('Access-Control-Allow-Headers:Origin, X-Requested-With, Content-Type, Accept, Authorization')

預檢請求成功以後,瀏覽器就會進行正常 CORS 請求。

參考:

http://www.ruanyifeng.com/blog/2016/04/cors.html

https://www.jianshu.com/p/7257e7c60ef5

https://www.jianshu.com/p/89a377c52b48

相關文章
相關標籤/搜索