4 / 11 詳講cors跨域資源共享

前面的話

前端日問,鞏固基礎,不打烊!!!

解答

之前小柒也總結過九種跨域方法(裏面有相關實例),這篇文章參考阮一峯老師的文章詳細梳理一下cors。

簡述

cors - 跨域資源共享,需要瀏覽器和服務器同時支持, 這種通信方式原理其實就是通過自定義http的頭部來進行通信。

兩種請求

  • 簡單請求:比如POSTGETHEAD
  • 非簡單請求:比如PUTDELET或者Content-Type字段類型爲application/json
簡單請求

如果是簡單請求的,瀏覽器直接發出CORS請求,會自動帶上Origin字段(指定請求來自哪個域名)。

當服務端收到響應後:

  • 如果Origin指定的源不在服務器允許的範圍內,那麼服務端會返回一個正常的HTTP迴應。但是這個響應是不帶Access-Control-Allow-Origin字段的,瀏覽器發現響應頭沒有包含這個字段,就知道出錯了,就會拋出一個錯誤。(這個錯誤是由XMLHTTPRequest的onerror回調函數捕獲的)。

  • 如果Origin指定的源在服務器允許的範圍內,那麼服務端返回的響應頭就會帶上。Access-Control-Allow-Origin字段,指定爲Origin字段的值,或者是* 表示接受任意域名的請求。(這個字段是必須的

    還可以攜帶其他的字段:比如Access-Control-Allow-Credentials(允許攜帶cookie) 、Access-Control-Expose-Headers(允許XMLHTTPRequest對象的getResponseHeader()拿到響應頭的其他字段的值)。

跨域如何攜帶cookie

如果想要攜帶cookie,必須瀏覽器與服務器同時支持

  • 瀏覽器必須開啓XMLHTTPRequest對象的WithCredentials屬性值爲true.

     xhr.withCredentials = true;// 前端設置是否帶cookie
    
  • 服務器響應頭要攜帶Access-Control-Allow-Credentials字段的值爲true.

      // 允許攜帶cookie
      res.setHeader('Access-Control-Allow-Credentials', 'true');
    

注意:如果攜帶了cookie,那麼服務器的Access-Control-Allow-Origin字段就不能設置爲*,必須指明的域名。

非簡單請求

預檢請求

如果是非簡單請求,那麼正式的CORS通信前,會進行一次預檢請求。瀏覽器會先詢問服務器,當前請求的域名是否被服務器所允許,如果服務器允許的話,纔會進行正式的通信。

看一段瀏覽器的腳本文件:

var  url = "http://localhost:8084";
var xhr = new XMLHTTPRequest();
xhr.open("PUT",url,true);
// 設置自定義請求頭字段:name
xhr.setRequestHeader('name',"xiaoqi")
xhr.send();

瀏覽器發現這是一個非簡單請求,就會自動發出一個預檢請求,預檢請求的方法是OPTIONS。

針對上面的腳本,對應預檢請求頭信息:

OPTIONS /cors HTTP/1.1
Origin: http://localhost:8081
Access-Control-Request-Method: PUT 
Access-Control-Request-Headers:name
Connection:keep-alive

可以看到,除了Origin字段外,還包括兩個特殊的字段:Access-Control-Request-Method該字段必須,用來列出瀏覽器CORS請求會用到的HTTP請求方法)、Access-Control-Request-Headers(指定瀏覽器CORS請求會額外發送的頭信息字段)

預檢請求迴應

服務器相應的頭信息設置,服務器設置,哪些域名可以訪問,支持的方法,是否可以攜帶cookie等

  		// 設置哪個源可以訪問我
        res.setHeader('Access-Control-Allow-Origin', origin);
        // 允許攜帶哪個頭來訪問我
        res.setHeader('Access-Control-Allow-Headers', 'name');
        // 允許哪個方法訪問我
        res.setHeader('Access-Control-Allow-Methods', 'PUT');
        // 允許攜帶cookie
        res.setHeader('Access-Control-Allow-Credentials', 'true');
        // 預檢的存在時間
        res.setHeader('Access-Control-Max-Age',6);
        // 允許返回的頭
        res.setHeader('Access-Control-Expose-Headers', 'name');

當服務器收到預檢請求之後,會檢查OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段後,如果允許,就會做出迴應:

響應頭會帶上的字段有:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://localhost:8081 
Access-Control-Allow-Methods: PUT
Access-Control-Allow-Headers: name
Access-Control-Allow-Credentials: true
...

如果預檢請求沒有被通過,服務器會返回一個正常的HTTP迴應,但是沒有任何CORS相關的頭信息字段。這時,瀏覽器就會知道服務器不同意這次預檢,返回一個錯誤,被XMLHttpRequest對象的onerror回調函數捕獲 。

正常請求

服務器通過預檢請求,以後每次瀏覽器正常CORS請求,都會和簡單請求一樣,會有一個Origin字段,服務器的迴應也會有Access-Control-Allow-Origin頭信息字段

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章