http請求發生了兩次(options請求)

前言

自後臺restful接口流行開來,請求了兩次的狀況(options請求)愈來愈廣泛。筆者也在實際的項目中遇到過這種狀況,作一下整理總結。angularjs

文章書寫思路:

爲何發生兩次請求

http的請求方式,包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT等八種請求方式。其中,get與post只是咱們經常使用的請求方式。json

咱們能在圖一里看到,第一條的請求方式爲options,第二條請求,纔是咱們預想中的請求。因此爲何發生兩條請求的緣由就變成了爲何發生options請求。跨域

 options請求

options請求的官方定義:OPTIONS方法是用於請求得到由Request-URI標識的資源在請求/響應的通訊過程當中可使用的功能選項。經過這個方法,客戶端能夠在採起具體資源請求以前,決定對該資源採起何種必要措施,或者瞭解服務器的性能。瀏覽器

用白話說就是:在發生正式的請求以前,先進行一次預檢請求。看服務端返回一些信息,瀏覽器拿到以後,看後臺是否容許進行訪問。服務器

如何產生options請求:

產生options請求的緣由包括如下幾條:restful

1:產生了複雜請求。複雜請求對應的就是簡單請求。簡單請求的定義是:cookie

  1.  請求方法是GET、HEAD或者POST,而且當請求方法是POST時,Content-Type必須是application/x-www-form-urlencoded, multipart/form-data或着text/plain中的一個值。
  2.  請求中沒有自定義HTTP頭部。

所謂的自定義頭部,在實際的項目裏,咱們常常會遇到須要在header頭部加上一些token或者其餘的用戶信息,用來作用戶信息的校驗。app

2:發生了跨域。框架

options請求有什麼做用

官方將頭部帶自定義信息的請求方式稱爲帶預檢(preflighted)的跨域請求。在實際調用接口以前,會首先發出一個options請求,檢測服務端是否支持真實的請求進行跨域的請求。真實請求在options請求中,經過request-header將 Access-Control-Request-Headers與Access-Control-Request-Method發送給後臺,另外瀏覽器會自行加上一個Origin請求地址。服務端在接收到預檢請求後,根據資源權限配置,在response-header頭部加入access-control-allow-headers(容許跨域請求的請求頭)、access-control-allow-methods(容許跨域請求的請求方式)、access-control-allow-origin(容許跨域請求的域)。另外,服務端還能夠經過Access-Control-Max-Age來設置必定時間內無須再進行預檢請求,直接用以前的預檢請求的協商結果便可。瀏覽器再根據服務端返回的信息,進行決定是否再進行真實的跨域請求。這個過程對於用戶來講,也是透明的。post

另外在HTTP響應頭,凡是瀏覽器請求中攜帶了身份信息,而響應頭中沒有返回Access-Control-Allow-Credentials: true的,瀏覽器都會忽略這次響應。

總結:只要是帶自定義header的跨域請求,在發送真實請求前都會先發送OPTIONS請求,瀏覽器根據OPTIONS請求返回的結果來決定是否繼續發送真實的請求進行跨域資源訪問。因此複雜請求確定會兩次請求服務端。

options請求如何避免


其實經過以上的分析,咱們能得出如下解決方案:

1:使用代理,避開跨域。

2:將複雜跨域請求更改成簡單跨域請求。

3:不使用帶自定義配置的header頭部。

 實際案例

筆者如今維護的項目之一是用angularjs做爲框架,使用$resoruce進行的通訊,請求頭默認採用content-type: application/json。因此即便拿掉請求頭裏前臺自定義的token,仍然還會在post請求中額外發出options請求,由於不知足簡單請求的條件。而get請求沒有這這個狀況。

 

筆者將header頭裏的token拿掉後,get的options請求消除了。

上圖中,post發出了options請求。緣由在於content-type。

去除post的options請求:

有人想問不想用options請求,卻又想驗證用戶信息該怎麼作呢?這個時候考慮經過cookie進行。

相關文章
相關標籤/搜索