[轉] 重定向 CORS 跨域請求

  • 簡單請求不可重定向,包括第一個preflight請求和第二個真正的請求都不行。
  • 簡單請求能夠重定向任意屢次,但如需兼容多數瀏覽器,只可進行一次重定向。
  • 中間服務器應當一樣配置相關 CORS 響應頭。

中間服務器設置

當跨域請求被重定向時,中間服務器返回的 CORS 相關的響應頭應當與最終服務器保持一致。 任何一級的 CORS 失敗都會致使 CORS 失敗。這些頭字段包括Access-Control-Allow-Origin, Access-Control-Allow-Credentials等。html

響應 preflight 的頭字段包括Access-Control-Allow-Headers, Access-Control-Allow-Methods等。 由於 preflight 不容許重定向(見下文),因此中間服務器也就沒必要管這些 preflight 頭字段。git

若是中間服務器未設置Access-Control-Allow-Origin,在 Chrome 中的錯誤信息爲:github

XMLHttpRequest cannot load http://mid.com:4001/redirect. 
Redirect from 'http://mid.com:4001/redirect' to 'http://index.com/access-control-allow-origin-wildcard' 
has been blocked by CORS policy: 
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'http://index.com:4001' is therefore not allowed access.

若是最終服務器未設置Access-Control-Allow-Origin,在 Chrome 中的錯誤信息爲:跨域

XMLHttpRequest cannot load http://index.com:4001/access-control-allow-origin-not-set. 
No 'Access-Control-Allow-Origin' header is present on the requested resource. 
Origin 'null' is therefore not allowed access.

Origin 變成 null 的解釋見下文。瀏覽器

重定向preflight 請求

任何非 2xx 狀態碼都認爲 preflight 失敗, 因此 preflight 不容許重定向。各瀏覽器表現一致再也不贅述,可參考 W3C:服務器

The following request rules are to be observed while making the preflight request:cookie

  • If the end user cancels the request Apply the abort steps.cors

  • If the response has an HTTP status code that is not in the 2xx range Apply the network error steps.tcp

– W3C CORS Recommandation: Cross-Origin Request with Preflight測試

重定向簡單請求

對於簡單請求瀏覽器會跳過 preflight 直接發送真正的請求。 該請求被重定向後瀏覽器會直接訪問被重定向後的地址,也能夠跟隨屢次重定向。 但重定向後請求頭字段origin會被設爲"null"(被認爲是 privacy-sensitive context)。 這意味着響應頭中的Access-Control-Allow-Origin須要是*或者null(該字段不容許多個值)。

即便瀏覽器給簡單請求設置了非簡單頭字段(如DNT)時,也應當繼續跟隨重定向且不校驗響應頭的DNT (由於它屬於User Agent Header,瀏覽器應當對此知情)。 參考 W3C 對簡單請求的處理要求

If the manual redirect flag is unset and the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the redirect steps. – W3C CORS Recommendation

OSX 下 Chrome 的行爲是標準的,即便設置了DNT也會直接跟隨重定向。

Safari 的怪異行爲

Safari 在設置DNT字段後,會向重定向後的地址首先發起 preflight(多是它忘記了該頭部是本身設置的?)。 這一行爲在桌面 Safari 的隱身模式,以及 iOS 不少瀏覽器中均可以觀察到。 Safari 遠程調試 iPhone,遇此行爲調試器會崩掉(筆者試了3個 Mac+iPhone Pair)。 建議使用tcpdump或者寫一個簡單的 CORS 服務器來調試。 在 OPTIONS 請求中,會帶有Access-Control-Request-Headers來聲明須要發送dnt

Access-Control-Request-Headers: 'dnt, accept-language, origin'

這意味着爲了 Safari 系列的瀏覽器(包括 iOS 平臺的多數瀏覽器), 重定向簡單 CORS 請求仍然須要實現 OPTIONS 方法(雖然咱們發的只是是簡單請求)。 而且在Access-Control-Allow-Headers響應頭字段添加dnt聲明。 不然 Safari 會認爲 CORS 失敗:

XMLHttpRequest cannot load http://index.com:4001/access-control-allow-origin-wildcard.
Request header field DNT is not allowed by Access-Control-Allow-Headers.

爲了輕鬆地讓 CORS preflight 成功,測試環境中能夠簡單地將請求頭Access-Control-Request-Headers的內容直接設置到響應頭的Access-Control-Allow-Headers

重定向非簡單請求

非簡單請求是 preflight 成功後才發送實際的請求。 preflight 後的實際請求不容許重定向,不然會致使 CORS 跨域失敗。

雖然在 Chrome 開發版中會對重定向後的地址再次發起 preflight,但該行爲並不標準。 W3C Recommendation中提到真正的請求返回301302303307308都會斷定爲錯誤:

This is the actual request. Apply the make a request steps and observe the request rules below while making the request. If the response has an HTTP status code of 301, 302, 303, 307, or 308 Apply the cache and network error steps. – W3C CORS Recommendation

在 Chrome 中錯誤信息是Request requires preflight, which is disallowed to follow cross-origin redirect

XMLHttpRequest cannot load http://mid.com:4001/cross-origin-redirect-with-preflight.
Redirect from 'http://mid.com:4001/cross-origin-redirect-with-preflight' to 'http://dest.com:4001/access-control-allow-origin-wildcard'
has been blocked by CORS policy: Request requires preflight,
which is disallowed to follow cross-origin redirect.

在 Safari 中的錯誤信息是Cross-origin redirection denied by Cross-Origin Resource Sharing policy.

XMLHttpRequest cannot load http://mid.com:4001/redirect.
Cross-origin redirection denied by Cross-Origin Resource Sharing policy.

屢次重定向的討論

屢次重定向涉及的一個關鍵問題是:preflight 後的請求不容許重定向。所以:

  • 對於簡單請求而且沒有任何 preflight 的狀況:瀏覽器會一直跟隨重定向(固然 HTTP 另有規定的除外,如 POST 被 302 時),直到最後一個請求返回或者中間請求的 CORS 驗證失敗(好比Access-Control-Allow-Origin設置錯誤)。
  • 對於簡單請求可是瀏覽器會發起 preflight 的狀況(好比 Safari 對 DNT 的處理):因 preflight 後重定向真正的請求會致使 CORS 失敗,因此屢次重定向是不可行的。
  • 對於非簡單請求:瀏覽器會直接發起 preflight,後續的重定向都是不容許的所以屢次重定向不可行。

總之,若是須要兼容大多數瀏覽器,不管是否爲簡單請求都不能夠屢次重定向

 

來源: https://harttle.land/2016/12/30/cors-redirect.html

相關文章
相關標籤/搜索