天天看點

#yyds幹貨盤點# 浏覽器跨域請求 原理和個人了解

什麼是跨域請求

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

我們可以按照業務需要,發出任意的http請求。

任意的http請求就是千奇百怪了,可以是對自家網站後端的http請求,也可以是對其他相關網站的請求。甚至于如果我們某些開發者、黑.客不懷好意,那就發起對某些網站的惡意的請求。

但是因為是在浏覽器之中,實際的所有的http請求自然是浏覽器發出的。

浏覽器出于安全考慮,并不是所有域名都可以直接通路。 浏覽器在發起任意的請求之前,浏覽器會判斷目标的url是不是和目前網站是來自相同的域名, 相同則一般認為是安全的,不同則被任務是跨域,此種請求就是跨域請求,它預設是不可信、不安全的。

(當然,如果不是由浏覽器發出的請求,那麼自然不是浏覽器的責任,比如ddos,就不屬于跨域請求的範疇了)

———— 這個就是對跨域請求的最簡單的了解。

#yyds幹貨盤點# 浏覽器跨域請求 原理和個人了解

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

#yyds幹貨盤點# 浏覽器跨域請求 原理和個人了解

什麼是普通請求

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

包括 同域請求、 從浏覽器位址欄發起請求。 

同域請求 就是浏覽器中某個頁面發起的對自家網站背景的請求。下面談談從浏覽器位址欄發起請求。

從浏覽器位址欄發起請求

那麼 浏覽器從位址欄發起的任意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,那麼控制台報錯,不發送正式請求。

#yyds幹貨盤點# 浏覽器跨域請求 原理和個人了解

如果浏覽器判斷是簡單請求,

那麼就無需先發起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

繼續閱讀