瀏覽器的同源策略和跨域詳解(內含故事解析)


前言

去年這個時候有寫過一篇文章叫《ajax中的json和jsonp詳解》,寫這個文章是因為我朋友學習前端剛好遇到了這個問題,但是就在昨天,他在學習java的時候又遇到同樣的問題,看來我又要操作一波了。(實則我就他這一個朋友)(๑→ܫ←)

提綱內容
  • 重述一遍何為同源策略(因為之前講過)
  • 跨域的三種方式
  • 剖析CORS方式跨域(重點)
  • 故事解析(次重點)

何為同源策略

同源策略就是協議相同、域名相同、端口相同相同的網頁才能資源互通。
簡單的來說,分為三個,我訪問淘寶網站,再訪問京東網站,這兩者資源肯定不能互通是吧。
1、也就是cookie和LocalStorage、IndexDB等無法互通。
2、DOM無法獲取
3、AJAX 請求在瀏覽器端有跨域限制

也就是說幾乎所有的請求都會跨域,why?主要還不是因為很多公司為了解決web訪問對后台造成壓力,都會把web服務器和后台接口服務器分到不同的域中,前后端不分離除外,另一個原因是前端開發人員調用后台測試,測試服務器在后台,web卻運行在自己電腦上。一個是localhost,一個是對應測試服務器的域名。

跨域的三種方式

剖析CORS方式跨域

CORS是一個W3C標准,全稱是"跨域資源共享"(Cross-origin resource sharing)

CORS可以理解為后端配置一些東西,主動同意哪些不同域名可以請求我的接口,從而實現跨域請求的問題,(對了,提示一下,jsonp雖然簡單好用,但是只能實現get請求,所以比較單一。但是jsonp可以適用於所有瀏覽器,CORS對ie只適用於ie10及以上,對其他瀏覽器都是支持的。)

先上一張圖(后面你會回來看的)

瀏覽器將cors請求分為兩類,簡單請求和非簡單請求,阮一峰在跨域資源共享 CORS 詳解一文中作了很詳細的區分,滿足一下兩大條件就是簡單請求,否則就是非簡單請求。如下:

1、請求方法是以下三種方法之一:
* HEAD
* GET
* POST
2、HTTP的頭信息不超出以下幾種字段:
* Accept
* Accept-Language
* Content-Language
* Last-Event-ID
* Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain

簡單請求按鈕(我朋友寫的就是簡單請求,但是服務器並沒有做cors配置),請求如下:

如第一張圖的執行流程,會在請求頭增加Origin字段為"http 😕/localhost"到后端,后端去檢測Origin信息,此時檢查的請求頭部有沒有自定義的,那么問題來了。
1、為毛要再次檢查請求頭?因為你前端信息為不可信信息,別人可以偽造瀏覽器請求加入Origin信息,並且自定義請求頭。
2、自定義請求頭有哪些定義有哪些?

  • Accept:用來告知(服務器)客戶端可以處理的內容類型
  • Accept-Language:允許客戶端聲明它可以理解的自然語言,以及優先選擇的區域方言
  • Content-Language:是一個 entity header (實體消息首部),用來說明訪問者希望采用的語言或語言組合,這樣的話用戶就可以根據自己偏好的語言來定制不同的內容
  • Content-Type實體頭部用於指示資源的MIME類型 media type(不屬於簡單請求的三個的任何一個)
  • DPR
  • Downlink
  • Save-Data
  • Viewport-Width
  • Width

他調這個接口的時候並沒有自定義頭部,只有設置了Content-Type為application/x-www-form-urlencoded,但是這並不影響,所以現在到了判斷是否符合要求的位置,什么符合要求呢?但是當然是跨源資源共享驗證,但是他后台並沒有配置任何的跨域訪問,所以所有的跨域請求多會被拒絕門外,但是信息是正常返回的,只不過返回頭里面沒有加Access-Control-Allow-Origin這個字段,如圖一所示。
這是時候會發生什么情況呢?截兩張圖就知道了。

what?
瀏覽器確實收到消息,但是他就是不給你,並且告訴你,你小子跨域了,並且服務器不同意你的跨域請求,所以就直接拋一個錯誤給你,你自己看着辦吧!

非簡單請求步驟就多了一步

在不滿足簡單請求的情況之下(就是非簡單請求),此時,如圖一所示,並不直接發送請求,而是發送一個OPTIONS預檢請求(所以下次看到OPTIONS請求的時候就知道這其實是一個前菜,好戲在后頭呢。嘻嘻),后台也是去做一個跨源資源共享驗證,他這里沒有配置,當然不成功,所以還是正常返回,這次返回頭里不僅不給返回Access-Control-Allow-Origin,而且不會有任何響應主體(如果你不配置的話),這也就是為啥后來他胡亂配置一通后發現post請求竟然變成OPTIONS請求了,然后不傳數據還不給返回數據的原因。請求視圖如下:

(細心了小伙伴會發現多了兩個字段,一看就明白,不用解釋了。嘻嘻)

怕他看不懂,所以這里也用一個小故事稍微解析一下子

首先來建立三個角色,小明(請求代碼,也可以說是開發者)、課代表(瀏覽器)、老師(服務器)

  • 簡單請求:
    小明(請求代碼)做了一份試卷(請求包)交給課代表(瀏覽器),課代表分析得出,這是一份簡單試卷(簡單請求),然后寫上這是這是一班的試卷(加上Origin字段),並且告訴老師這是一份簡單試卷,老師(服務器)拿到試卷后,就開始閱讀。
    首先看這個題(請求頭部),是不是簡單的試卷,畢竟課代表說的話不可信。
    如果不簡單就直接丟了,如果是簡單試卷就再看看課代表寫的是幾班的試卷。
    老師說我只改一班和三班的試卷(跨源資源共享驗證),剛好這是一班的試卷,所以就改完直接還給課代表了,課代表發現沒有異樣就直接給小明了。
    如果這不巧是二班的試卷,老師還是把試卷給改出來(服務器返回正常的結果),但是同時在試卷上加上一句話,“我是一班和三班的老師,以后不要發二班的試卷給我了(返回頭中沒有Access-Control-Allow-Origin字段)”。
    課代表大發雷霆,不僅不把試卷(服務器正常結果)給小明,還警告小明(拋出錯誤)。

  • 非簡答請求:
    小明(請求代碼)做了一份試卷(請求包)交給課代表(瀏覽器),課代表分析得出,這是一份很難的試卷(非簡單請求),然后課代表寫一封信(OPTIONS請求,里面寫上這是一班的試卷)給老師。
    老師收到這封信,老師改一班和三班的試卷,所以就批改這封信(后台設置返回的信息,不設置是沒有返回主體的),ok,沒問題,請把試卷給我(返回頭中有Access-Control-Allow-Origin字段)。
    然后課代表發現信沒有異樣,后面的流程就像批改簡單試卷流程一樣了。
    如果,課代表發送的信里寫這的是“這是二班的試卷”,那么,老師還是會批改這封信,然后正常返回這封信。關鍵是老師又加上那句話“我是一班和三班的老師,以后不要發二班的試卷給我了(返回頭中沒有Access-Control-Allow-Origin字段)”,所以,試卷根本就沒有發給老師。

  • 注意
    簡單請求是只有一次請求的,非簡單請求是兩次請求。然后一切都透徹了啊!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM