CORS跨域時,爲什麼會出現一次動做,兩次請求?

提出問題

在開發先後端分離項目時候,咱們總會面臨一個跨域問題。前端

衆所周知,在之前,跨域能夠採用代理、JSONP等方式,而在現代瀏覽器面前,咱們有了更好的選擇,CORSajax

咱們能夠經過服務器端設置Access-Control-Allow-Origin響應頭,便可使指定來源像訪問同源接口同樣訪問跨域接口。後端

在使用CORS的時候,後臺採用token檢驗機制,前臺發送請求必須將token放到Request Header中,那麼就須要傳輸自定義Header信息,這時候細心的你必定會發現一個問題,在前端ajax請求數據的時候,有時候會向後臺一次性發送兩次請求,這兩次請求第一次無返回數據,第二次纔會返回正確數據。像下圖這個樣子,莫名多出了一個 OPTIONS 的請求:跨域

不用懷疑,這不是你的代碼有bug,也不是在請求函數中重複調用了請求,由於很明顯,兩次的 Request Method 是不同的。瀏覽器

若是你也曾因這個問題,困惑過,迷茫過,不知所因。那麼關於這個問題,我將爲你給出答案!服務器

對於CORS跨域,有兩種不一樣的請求類型。cookie

  • 簡單跨域請求
  • 複雜跨域請求(帶預檢的跨域請求)。

簡單跨域請求

簡單跨域請求是指知足如下兩個條件的請求。 一、HTTP方法是如下三種方法之一:app

  • HEAD
  • GET
  • POST

二、HTTP的頭信息不超出如下幾種字段:前後端分離

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限於三個值,application/x-www-form-urlencoded、multipart/form-data、text/plain

簡單跨域請求的部分響應頭以下:函數

  • Access-Control-Allow-Origin(必含)- 不可省略,不然請求按失敗處理。該項控制數據的可見範圍,若是但願數據對任何人均可見,能夠填寫"*"。

  • Access-Control-Allow-Credentials(可選) – 該項標誌着請求當中是否包含cookies信息,只有一個可選值:true(必爲小寫)。若是不包含cookies,請略去該項,而不是填寫false。這一項與XmlHttpRequest2對象當中的withCredentials屬性應保持一致,即withCredentials爲true時該項也爲true;withCredentials爲false時,省略該項不寫。反之則致使請求失敗。

  • Access-Control-Expose-Headers(可選) – 該項肯定XmlHttpRequest2對象當中getResponseHeader()方法所能得到的額外信息。一般狀況下,getResponseHeader()方法只能得到以下的信息:

    • Cache-Control
    • Content-Language
    • Content-Type
    • Expires
    • Last-Modified
    • Pragma

    當你須要訪問額外的信息時,就須要在這一項當中填寫並以逗號進行分隔。

複雜跨域請求

任何一個不知足簡單跨域請求要求的請求,即被認爲是複雜請求,也稱做帶預檢的跨域請求。

一個複雜請求不止發送一個包含通訊內容的請求,其中最早發送的是一種**"預檢"請求**,此時做爲服務端,也須要返回**"預迴應"**做爲響應。"預檢"請求其實是對服務端的一種權限請求,只有當"預檢"請求成功返回,實際請求才開始執行。

預請求以OPTIONS形式發送,當中一樣包含域,而且還包含了兩項CORS特有的內容:

  • Access-Control-Request-Method – 該項內容是實際請求的種類,能夠是GET、POST之類的簡單請求,也能夠是PUT、DELETE等等。
  • Access-Control-Request-Headers – 該項是一個以逗號分隔的列表,當中是複雜請求所使用的頭部。

顯而易見,這個"預檢"請求實際上就是在爲以後的實際請求發送一個權限請求,在預迴應返回的內容當中,服務端應當對這兩項進行回覆,以讓瀏覽器肯定請求是否可以成功完成。一旦預迴應如期而至,所請求的權限也都已知足,纔會發出真實請求,攜帶真實數據。

解決方法

如今問題所在已經很明顯了,那麼面對這種跨域預檢機制形成的屢次請求問題,咱們能夠在後臺設置Access-Control-Max-Age來控制瀏覽器在多長時間內(單位s)無需在請求時發送預檢請求,從而減小沒必要要的預檢請求。

關於CORS的更細緻的問題能夠查看MDN

相關文章
相關標籤/搜索