瀏覽器跨域請求 原理和個人理解

 

什麼是跨域請求
我們知道,我們web的網站的網頁,會展示在瀏覽器中,其中的按鈕、或者腳本等等可以觸發事件、發起http請求的。至於發送什麼樣的http請求,那完全就是我們開發者(網站開發者)設計的。

我們可以按照業務需要,發出任意的http請求。 任意的http請求就是千奇百怪了,可以是對自家網站後端的http請求,也可以是對其他相關網站的請求。甚至於如果我們某些開發者、黑.客不懷好意,那就發起對某些網站的惡意的請求。 但是因爲是在瀏覽器之中,實際的所有的http請求自然是瀏覽器發出的。

瀏覽器出於安全考慮,並不是所有域名都可以直接訪問。 瀏覽器在發起任意的請求之前,瀏覽器會判斷目標的url是不是和當前網站是來自相同的域名, 相同則一般認爲是安全的,不同則被任務是跨域,此種請求就是跨域請求,它默認是不可信、不安全的。 (當然,如果不是由瀏覽器發出的請求,那麼自然不是瀏覽器的責任,比如ddos,就不屬於跨域請求的範疇了) ———— 這個就是對跨域請求的最簡單的理解。

 

 

 

至於什麼是相同域名、不同域名, 其實也很簡單,這裏不在贅述。

 

 

 

 

 

什麼是普通請求
其實並沒有什麼普通請求,這個是我自己對請求的分類。我們可以把非跨域請求理解爲普通請求。

包括 同域請求、 從瀏覽器地址欄發起請求。 

同域請求 就是瀏覽器中某個頁面發起的對自家網站後臺的請求。下面談談從瀏覽器地址欄發起請求。

 

從瀏覽器地址欄發起請求
那麼 瀏覽器從地址欄發起的任意url的請求, 和 瀏覽器從 頁面發起的跨域的請求, 有什麼區別嗎?

區別肯定是有的, 瀏覽器從地址欄發起的任意url的請求, 不會有referer,不存在跨域問題。

所以,從瀏覽器地址欄發起請求 都是普通請求!

瀏覽器從頁面發起的任意url的請求,會有referer, ( 是不是必然有呢? )

然後 目標域名的服務器會檢查是不是自己的域名發起的請求 ———— 這個是 web 服務器的常規操作。(是否可以禁用呢? )

如果來源是, 即referer是 自己域名的url,一般不會拒絕。如果不是, 那麼可以選擇拒絕以防止csrf 等攻.擊,然後就不返回 任何內容? 還是返回一個 cors error 的響應頭呢? 這個都是可以設置的,關鍵在於後端服務器。

 

普通請求和跨域請求 的區別
普通請求是 沒有的, 而 跨域請求會多一個請求頭,比如Origin: http://localhost:9999, 表示自己的 域名,( 包括 options 請求也會多 一個 Origin請求頭, 如果有options 請求的話 )

 

這個 Origin請求頭, 自然是瀏覽器在判斷不是相同的域名之後添加的。 web 服務器就代表了其前端的資源—— 因爲其對外提供的訪問服務:包括頁面、json 等任何資源 (包括前端瀏覽器 能展示的, 不能展示的 ) 也都是來自於 web server端,即服務端。

一個 web server端 可以認爲代表了一個域、一個域名。 瀏覽器可以任意方式發起一個對 任意域名 的訪問, 從瀏覽器地址欄, 某個瀏覽器頁面的 按鈕、頁面的html 源碼觸發,或者js 觸發。

一般而言,瀏覽器可以在地址欄發起任意url 的請求,但是 瀏覽器 一般都是不允許在 頁面內發起對其他域的請求。 當然, 也不是完全不行,只是默認不行。

 

簡單請求和非簡單請求
瀏覽器將CORS請求,即跨域請求分爲兩類:簡單請求(simple request)和非簡單請求(not-simple-request)

簡單請求瀏覽器不會預檢,而非簡單請求會預檢。這兩種方式怎麼區分?

 

首先搞懂什麼是非簡單請求, 它包括:

1 請求方式是PUT或者DELETE,

2 或者Content-Type字段類型是application/json,

3 包括其他自定義的請求頭 的請求。

除去非簡單請求,那麼其他的就是簡單請求了,一個簡單的非此即彼的分類。

實際上, 在發起跨域請求的時候,瀏覽器會先判斷是否是非簡單請求,

如果是非簡單請求,
那麼會先發起對目標域名的 options請求,即預檢請求。 如果目標域名的服務器允許了, 那麼在發起正式的請求。預檢請求通過了,此時發起正式請求一般都會通過吧... 此時就被禁止的可能性就不大(個人認爲)。 如果預檢請求不通過,比如瀏覽器通過預檢請求響應發現,目標域名的服務器不允許當前網站發送跨域請求,或者不允許POST,那麼控制檯報錯,不發送正式請求。


如果瀏覽器判斷是簡單請求,
那麼就無需先發起options請求了,直接發起正式請求。此時發起的正式請求,仍然很可能被服務端禁止,被禁止的話,瀏覽器控制檯通常會拋出cors xxx之類的錯誤。。

 

 

 

 

總結一下就是:

簡單請求:   一次: 正式請求

非簡單請求:  兩次:預檢請求+ 正式請求;

 

爲什麼要做這樣的區分?爲什麼要對非簡單跨域請求先發起options請求呢? 大概是爲了更加的安全、保險起見。我估計是因爲:

1 put、delete 操作一般認爲是新增、刪除, 自然需要謹慎些。

2 Content-Type字段類型是application/json 那麼可能是xhr 等發起的請求,xss、csrf 可能性更大。

3 包括其他自定義的請求頭 的請求,同上,其可能是xhr等發起的請求,xss、csrf 可能性更大

 

跨域請求的細節
瀏覽器處理跨域請求的時候,基本是通過請求頭、響應頭處理的。

請求頭關鍵是:
Origin

Access-Control-Request-Headers: content-type

Access-Control-Request-Method: POST

 

響應頭的關鍵是:
Access-Control-Allow-Headers: content-type

Access-Control-Allow-Methods: GET,HEAD,POST

Access-Control-Allow-Origin: http://localhost:8080

Access-Control-Expose-Headers: X-Powered-By

如果設置了.allowCredentials(true) ,那麼 會多一個 Access-Control-Allow-Credentials: true

 

當然,整個過程其實還是有一些複雜的,本文只是做個簡單介紹。更多的細節請等待我的後續文章。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章