CORS 理解(不要那麼多術語)

摘要

談到跨域,不論前端仍是後端,多少有點談虎色變,面試中也常會問到這些問題,瀏覽器和服務器端到底怎麼作才能跨域,他們都作了什麼?html

同源 vs 跨域

同源,字面意義是相同的源頭,即同一個web服務器(好比tomcat啓動的一個實例),比如一個家庭;跨域就是從一個web服務器向另外一個服務器發送或獲取數據,比如去鄰居家拿東西。之因此要作跨域限制,是爲了安全,你不能從鄰居家直接拿吧,總得問過人家。前端

那麼怎麼來判斷同源?就看一個web服務器的根本三要素:協議、web服務器域名、端口號。web

好比:當前頁面的地址是http://myhost.com:8080/index,源就是http://myhost.com:8080,當新請求的協議、域名、端口號與之徹底一致便是同源,不然是跨域。面試

對於下面發送的請求,瀏覽器的判決以下:ajax

  • http://www.myhost.com:8080/users 跨域 -> 域名必須徹底一致
  • https://myhost.com:8080/users 跨域 -> 協議必須一致
  • https://myhost.com:9000/users 跨域 -> 端口必須一致
  • https://myhost.com/users 跨域 -> 端口必須一致(沒有端口也是不一致)
  • https://myhost.com:8080/profile/users 同源

跨域時的動做

瀏覽器端

假設咱們點擊一個按鈕去獲取數據,獲取數據的請求準備從瀏覽器發出,這時瀏覽器先會檢測這條請求是同源仍是跨域,也就是與按鈕所在頁面的地址是同源仍是跨域,若是是同源,好說,直接發送出去;若是是跨域的請求,那就得hold住先,瀏覽器會在請求的http header中加上一個Origin字段,標明這個請求是從哪裏發出來的,例如: Origin:http://neighbour.com:9000,這樣服務器端好辨識是本身家人來取東西,仍是隔壁老王來借東西了。json

那些作檢測、加header字段等事情全是瀏覽器作,對於前端開發者來講,什麼事都不用幹,ajax請求平時怎麼發送,跨域時還怎麼發送。可見,跨域對於前端沒影響,關鍵在於服務器端。後端

服務器端

每一個web服務器就像一個家庭。好鄰居要吃螃蟹來借點醋,這沒問題;壞鄰居家有醋要來借點螃蟹,這不幹。跨域

服務器收到請求會給與響應,響應的header裏寫明跨域的配置信息,告訴瀏覽器,它容許哪些域名發來的請求訪問,哪些method能夠執行。瀏覽器收到響應後自動判斷能不能真正執行請求。瀏覽器

假設服務器域名是http://rich.com:8080,它收到了一個從http://neighbour.com:9000發來的請求http://rich.com:9000/borrow-vinegar,服務器響應它,在響應中寫明本服務器支持哪些域名能夠訪問,哪些method能夠執行,瀏覽器收到後作匹配,再斷定。緩存

那麼,服務器有哪些斷定的規則呢?

是否容許跨域的斷定

一個支持CORS的web服務器,有以下的斷定字段,他們會在響應的header中寫明

  • Access-Control-Allow-Origin:容許跨域的Origin列表
  • Access-Control-Allow-Methods:容許跨域的方法列表
  • Access-Control-Allow-Headers:容許跨域的Header列表
  • Access-Control-Expose-Headers:容許暴露給JavaScript代碼的Header列表
  • Access-Control-Max-Age:最大的瀏覽器緩存時間,單位爲s

其中Access-Control-Allow-Origin(訪問控制之容許的源),在響應的http header中必須有的,表示容許訪問本服務器的源頭Origin(域名),能夠是特定的域名列表,用逗號分隔,也能夠是通配符 *,表示支持任意域名的訪問。

除了限定源頭Origin,還會限制請求的方法MethodHeader

如,若是服務器設定Access-Control-Allow-Methods:GET,那麼跨域的POST請求沒法在這個服務器執行。

總流程

  • 頁面發送請求
  • 瀏覽器根據同源策略作出斷定,若是是同源請求,直接發送出去;若是是跨域請求,在HTTP HEADER加上Origin字段,或是先發送一次預檢請求(preflight)。
  • 服務器接收請求,根據自身跨域的配置(如容許哪些域名,什麼樣的Method訪問),返回文件頭。若未配置過任何容許跨域,則文件頭裏不包含Access-Control-Allow-origin字段,若配置過域名,則返回Access-Control-Allow-origin+ 對應配置規則裏的域名的方式。
  • 瀏覽器接收到響應,根據響應頭裏的`Access-Control-Allow-origin字段作匹配,若是沒有這個字段,說明不匹配;若是有,將字段內容和當前域名作比對。如匹配,則能夠發送請求。

跨域的請求形式

跨域的請求分兩種,一種是簡單請求,一種是非簡單請求(廢話)。

  • 簡單請求,方法僅限於 HEAD,GET或POST,且Header的字段不超過如下字段:

    • HeadeAccept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain (沒有application/json, 說明若是發送JSON格式的body請求數據是一個非簡單請求)
  • 非簡單請求就是其餘請求

簡單請求瀏覽器會直接在請求的Header加上Origin字段再發送;非簡單請求瀏覽器則會先發送一次預檢請求,根據預檢請求的結果,決定是否正式發送請求。

詳情能夠訪問阮一峯的日誌:跨域資源共享 CORS 詳解

相關文章
相關標籤/搜索