CORS 跨域, 也許這篇就夠了

莫語發表於2018-12-12

CORS前奏

瞭解CORS跨域之前,也許我們還應該對跨域這麼個東東的一些概念要有些瞭解。

1. 什麼是跨域

廣義上的跨域是指一個 域下的文件或指令碼試圖去請求另一個域下的資源。比如: 資源跳轉(a連結)、資源嵌入(link, script)、指令碼請求(js發起ajax請求)等。而我們通常所討論的跨域是指的是狹義上的跨域,指的是由瀏覽器同源策略限制的一類請求場景。那麼什麼是同源策略,同源策略又限制了什麼。

2. 什麼是同源策略

同源指的是如果兩個頁面的協議,埠和域名都相同,則兩個頁面具有相同的源,只要其中之一不同,則那這兩個源就不相同。

3. 同源策略限制了什麼

  • Cookie、LocalStorage 和 IndexDB 無法讀取。
  • DOM 無法獲得(內嵌iframe中,父子頁面不能獲取DOM)。
  • AJAX 請求不能傳送。

4. 為什麼有同源策略的限制

同源政策的目的,是為了保證使用者資訊的安全,防止惡意的網站竊取資料。

  1. Cookie、LocalStorage 和 IndexDB 無法讀取限制。(原因比如:訪問一個惡意網站,獲取到所有網站下的cookie資訊, 如果有某個已登入的網站, 登入驗證放在cookie裡, 那就可以偽裝你的身份去訪問該 網站。)
  2. DOM 無法獲得(內嵌iframe中,父子頁面不能獲取DOM)。(原因比如:一個惡意 網站,iframe嵌入一個正規網站的, 這樣就可以獲取到使用者的登入資訊和密碼。 )
  3. AJAX 請求不能傳送。 (原因比如: 沒限制直接就可以用指令碼把伺服器給打爆了。)

5. 解決跨域的方法

  • JSONP
  • location.hash
  • document.domain
  • window.name
  • window.postMessage
  • WebSocket
  • CORS 接下來要重點討論下的是CORS是如何解決ajax請求跨域的。

CORS正文

CORS(跨域資源共享)是一種機制,允許 Web 應用伺服器進行跨域訪問控制,從而使跨域資料傳輸得以安全進行。CORS的使用要瀏覽器和服務端同時支援,並配合使用, IE要大於10。

1. 怎麼工作的

CORS請求過程
js中進行一個跨域的ajax請求,瀏覽器判斷該請求是簡單請求還是複雜請求,簡單請求就直接傳送, 複雜請求就先傳送一次預檢請求, 預檢請求成功後, 再傳送完整的請求, 整個過程對使用者是無感知的。那麼什麼是簡單請求和複雜請求呢?

2. CORS的簡單請求和複雜請求

簡單請求需要同時滿足以下兩個條件:

  • 請求是以下方法之一: GET、HEAD、POST
  • 不得人為設定以下集合之外的其他首部欄位:
Accept
Accept-Language
Content-Language
Content-Type (需要注意額外的限制):
(text/plain
multipart/form-data
application/x-www-form-urlencoded)
複製程式碼

非簡單請求就認為是複雜請求(比如PUT、DELETE請求, content-type設定為appliction/json等), 就需要傳送預檢請求。

3. CORS是如何工作的(如何確定是否允許跨域)

確定是否允許跨域就需要瀏覽器和伺服器共同協作完成,主要就是通過特定的一些響應頭來完成。預檢請求還需要有特定的請求頭。那麼特定請求頭分別有哪些以及是如何配合使用的。

######a. 服務端響應頭

  • Access-Control-Allow-Origin:這個欄位是必須的,代表的是允許跨域的源, '*'代表任意的源。
  • Access-Control-Allow-Methods: 這個欄位也是必須的, 代表允許跨域的http請求方法。
  • Access-Control-Allow-Credentials: 非必須的, 表示是否允許傳送cookie, 預設是false,如果設定為true則同時還需要客戶端要設定xhr.withCredentials = true才能起作用, 兩者是共存的(其中的cookie帶的是目標域的cookie)。
  • Access-Control-Allow-Headers: 非必須的,表示允許的請求頭, 如果預檢請求中包括了Access-Control-Request-Headers, 則服務端必須設定該欄位。
  • Access-Control-Max-Age:非必須的,用來指定本次預檢請求的有效期,單位為秒。即將CORS的響應配置快取在瀏覽器端, 在快取生效時間內,下次請求不用傳送預檢請求。 需要注意的是: 瀏覽器的disable-cache要關掉
  • Access-Control-Expose-Headers:可選欄位, 客戶端只能根據響應獲取到以下的響應頭:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
複製程式碼

如果想要獲取額外的響應頭資訊, 則需要將其設定在這個欄位中。

b. 客戶端預檢請求頭
  • Access-Control-Request-Method: 該欄位是必須的,用來表示覽器的CORS請求會用到哪個HTTP方法。
  • Access-Control-Request-Headers: 該欄位是非必須的,指定瀏覽器CORS請求額外傳送的頭資訊欄位。
針對簡單請求情況:

不會傳送預檢請求, 直接是發起真正的請求,只要 Access-Control-Allow-Origin與Access-Control-Allow-Methods正確的設定就能發起請求。

具體的coding例子:github傳送門

後記: 如果看完這篇還沒理解,那就。。。再多看幾遍(逃。。。),根據demo折騰下。

參考文章:

  1. www.ruanyifeng.com/blog/2016/0…
  2. www.html5rocks.com/en/tutorial…
  3. developer.mozilla.org/zh-CN/docs/…
  4. developer.mozilla.org/zh-CN/docs/…
  5. github.com/hijiangtao/…

相關文章