自後臺restful接口流行開來,請求了兩次的狀況(options請求)愈來愈廣泛。筆者也在實際的項目中遇到過這種狀況,作一下整理總結。angularjs
http的請求方式,包括OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE和CONNECT等八種請求方式。其中,get與post只是咱們經常使用的請求方式。json
咱們能在圖一里看到,第一條的請求方式爲options,第二條請求,纔是咱們預想中的請求。因此爲何發生兩條請求的緣由就變成了爲何發生options請求。跨域
options請求的官方定義:OPTIONS方法是用於請求得到由Request-URI標識的資源在請求/響應的通訊過程當中可使用的功能選項。經過這個方法,客戶端能夠在採起具體資源請求以前,決定對該資源採起何種必要措施,或者瞭解服務器的性能。瀏覽器
用白話說就是:在發生正式的請求以前,先進行一次預檢請求。看服務端返回一些信息,瀏覽器拿到以後,看後臺是否容許進行訪問。服務器
產生options請求的緣由包括如下幾條:restful
1:產生了複雜請求。複雜請求對應的就是簡單請求。簡單請求的定義是:cookie
所謂的自定義頭部,在實際的項目裏,咱們常常會遇到須要在header頭部加上一些token或者其餘的用戶信息,用來作用戶信息的校驗。app
2:發生了跨域。框架
官方將頭部帶自定義信息的請求方式稱爲帶預檢(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請求返回的結果來決定是否繼續發送真實的請求進行跨域資源訪問。因此複雜請求確定會兩次請求服務端。
其實經過以上的分析,咱們能得出如下解決方案:
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進行。