跨域就這麼點事兒

Xiaowei發表於2018-07-13

這篇文章主要介紹跨域方面的知識。

說跨域之前先說說同源策略,同源策略是一種約定,幾乎所有現代瀏覽器都遵循了這種約定,它也是一種安全策略,確保非同源的請求無法隨意請求,從而保證了網站的安全。同源需要保證協議,域名,埠都相同,只要有一個不同,那麼他們就不是同源的。雖然同源策略保證了安全性,但有時候我們確實需要非同源之間相互訪問,比如在前後端分離的專案中,前端和後端的地址分別為https://xwchris.mehttps://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

簡單請求要滿足以下條件:

  1. 請求方法必須是GETHEADPOST其中的一個
  2. HTTP資訊不能超過以下幾種欄位AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-TypeContent-Type的值只限於application/x-www-form-urlencodedmultipart/form-datatext/plain

瀏覽器傳送簡單請求時會自動在請求頭部新增Origin欄位,代表訪問源。

要支援CORS訪問需要伺服器在響應頭中新增Access-Control-Allow-Origin,可以使用*來表示允許所有域跨域訪問。

非簡單請求的CORS

非簡單請求與簡單請求最大的不同在於,它有一次預請求preflight的過程,只有這次請求校驗通過,才能傳送正常的請求。

預請求

預請求是OPTIONS請求,瀏覽器會自動新增Access-Control-Allow-HeadersAccess-Control-Allow-Methods

需要伺服器返回的響應頭包括Access-Control-Allow-HeadersAccess-Control-Allow-MethodsAccess-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請求,可以放心食用。原文地址:傳送門

相關文章