這篇文章主要介紹跨域方面的知識。
說跨域之前先說說同源策略,同源策略是一種約定,幾乎所有現代瀏覽器都遵循了這種約定,它也是一種安全策略,確保非同源的請求無法隨意請求,從而保證了網站的安全。同源需要保證協議,域名,埠都相同,只要有一個不同,那麼他們就不是同源的。雖然同源策略保證了安全性,但有時候我們確實需要非同源之間相互訪問,比如在前後端分離的專案中,前端和後端的地址分別為https://xwchris.me
和https://api.xwchris.me
。非同源之間跨域訪問就要用到CORS跨域方法。CORS全稱Cross Origin Resource Sharing
即跨域資源共享。
CORS跨域相關頭部
以下是幾種與跨域相關的頭部,及簡單的介紹。
- Access-Control-Allow-Headers(請求頭,響應頭,預請求)(攜帶Cookie情況下不能為*)
- Access-Control-Allow-Methods(請求頭,響應頭,預請求)(攜帶Cookie情況下不能為*)
- Access-Control-Allow-Origin(響應頭,預請求/正常請求)(攜帶Cookie情況下不能為*)
- Access-Control-Allow-Credentials(響應頭,預請求/正常請求)(攜帶Cookie情況下要設定為true)
- Access-Control-Max-Age(響應頭,預請求)(單位s)
簡單請求的CORS
簡單請求要滿足以下條件:
- 請求方法必須是
GET
、HEAD
和POST
其中的一個 - HTTP資訊不能超過以下幾種欄位
Accept
、Accept-Language
、Content-Language
、Last-Event-ID
和Content-Type
且Content-Type
的值只限於application/x-www-form-urlencoded
、multipart/form-data
和text/plain
。
瀏覽器傳送簡單請求時會自動在請求頭部新增Origin
欄位,代表訪問源。
要支援CORS訪問需要伺服器在響應頭中新增Access-Control-Allow-Origin
,可以使用*
來表示允許所有域跨域訪問。
非簡單請求的CORS
非簡單請求與簡單請求最大的不同在於,它有一次預請求preflight
的過程,只有這次請求校驗通過,才能傳送正常的請求。
預請求
預請求是OPTIONS
請求,瀏覽器會自動新增Access-Control-Allow-Headers
和Access-Control-Allow-Methods
。
需要伺服器返回的響應頭包括Access-Control-Allow-Headers
、Access-Control-Allow-Methods
和Access-Control-Allow-Origin
。
除了Access-Control-Allow-Origin
是必須的之外,其他兩種只有在不符合簡單請求需要的時候伺服器才需要新增,比如在簡單請求的基礎上自定義了一個請求頭X-xx-name: chris
,那麼伺服器只需要在響應頭中新增Access-Control-Allow-Headers
。每種響應頭都可以使用*
萬用字元來表示所有。
正常請求
預請求完之後就可以傳送正常請求了,正常請求的步驟與簡單請求一致,也需要新增Access-Control-Allow-Origin
響應頭。
減少預請求次數
可以通過設定Access-Control-Max-Aage
來減少預請求的次數,需要包含在預請求的響應頭中,指定在該時間內預請求驗證有效,不必每次都進行預請求,它的單位是s
。如Access-Control-Max-Age: 1728000
,即有效期為20天。
攜帶Cookie的請求
預設情況下,跨域請求不會攜帶Cookie,如果要攜帶Cookie進行跨域請求需要請求方和接收方同時支援。為了支援攜帶Cookie需要在請求的時候由開發者手動指定請求物件xhr.withCredentials=true
。伺服器響應頭需要包含Access-Control-Allow-Credentials: true
,如果是非簡單請求,預請求也需要包含該頭部。
這裡需要注意的是,在這種情況下所有需要的響應頭的值都不能是*
,在需要的情況下都需要明確指定。
其他跨域方法
除了CORS,我們還可以使用JSONP
技術來進行跨域,這是一種很古老的Hack。我們都是知道script
標籤可以訪問任何域下的指令碼,因此可以利用這種方法來進行跨域,這需要伺服器進行配合。舉個例子?:
<script type="text/javascript">
function getName(name) {
console.log(name);
}
</script>
<script src="http://api.xxx.com?callback=getName"></script>
複製程式碼
請求伺服器後伺服器需要拿到callback
欄位的值,然後將要返回的值變成JSON,放入getName
中。最終返回的值x像這個形式;getName({"name": "chris"})
,這樣getName函式就可以就可以拿到相應的值。
JSONP相比CORS,只能進行GET請求,但是相容性好一些。不過現代瀏覽器基本上都支援了CORS請求,可以放心食用。原文地址:傳送門