淺析http簡單請求與復雜請求


  詳細內容看這篇文檔,官方描述:Cross-Origin Resource Sharing (CORS):https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

  我們在開發網站時經常會用到跨域資源共享(簡稱cors)來解決跨域問題,但是在使用cors的時候,http請求會被划分為兩類,簡單請求和復雜請求,而這兩種請求的區別主要在於是否會觸發cors預檢請求。

  首先我們要明白cors的原理(引自MDN):

跨域資源共享標准新增了一組 HTTP 首部字段,允許服務器聲明哪些源站通過瀏覽器有權限訪問哪些資源。

另外,規范要求,對那些可能對服務器數據產生副作用的 HTTP 請求方法(特別是 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求),瀏覽器必須首先使用 OPTIONS 方法發起一個預檢請求(preflight request),從而獲知服務端是否允許該跨域請求。

服務器確認允許之后,才發起實際的 HTTP 請求。在預檢請求的返回中,服務器端也可以通知客戶端,是否需要攜帶身份憑證(包括 Cookies 和 HTTP 認證相關數據)。

  在涉及到CORS的請求中,我們會把請求分為簡單請求和復雜請求。

  從上面的文字中我們得到如下信息:

1、跨域資源共享標准新增了一組 HTTP 首部字段,服務器通過這些字段來控制瀏覽器有權訪問哪些資源。

2、為了安全起見請求方式分為兩類,一類不會預先發送options請求,一些會預先發送options請求。

3、 GET 以外的 HTTP 請求,或者搭配某些 MIME 類型的 POST 請求會觸發options請求。

4、服務器驗證OPTIONS完成后才會允許發送復雜的http請求。

  不會觸發http預檢請求的便是簡單請求,相反能夠觸發http預檢請求的便是復雜請求。

一、什么是簡單請求

  那么有哪些簡單請求呢?以下是來自MDN官方引用:

1、請求方法是以下三種方法之一:GET、POST、HEAD。

2、不能自定義請求頭header,不得人為設置該集合之外的其他首部字段。該集合為:Accept、Accept-Language、Content-Language、Content-Type

3、Content-Type 的值僅限於下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-http-urlencoded

4、請求中的任意XMLHttpRequestUpload 對象均沒有注冊任何事件監聽器;XMLHttpRequestUpload 對象可以使用 XMLHttpRequest.upload 屬性訪問

5、請求中沒有使用 ReadableStream 對象

  簡單請求的發送從代碼上來看和普通的XHR沒太大區別,但是HTTP頭當中要求總是包含一個域(Origin)的信息。該域包含協議名、地址以及一個可選的端口。不過這一項實際上由瀏覽器代為發送,並不是開發者代碼可以觸及到的。

  簡單請求的部分響應頭及解釋如下:

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也沒有什么大不了,但CORS的復雜請求就令CORS顯得更加有用了。簡單來說,任何不滿足上述簡單請求要求的請求,都屬於復雜請求。比如說你需要發送PUT、DELETE等HTTP動作,或者發送Content-Type: application/json的內容。

  復雜請求表面上看起來和簡單請求使用上差不多,但實際上瀏覽器發送了不止一個請求。其中最先發送的是一種"預請求",此時作為服務端,也需要返回"預回應"作為響應。預請求實際上是對服務端的一種權限請求,只有當預請求成功返回,實際請求才開始執行。

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

Access-Control-Request-Method – 該項內容是實際請求的種類,可以是GET、POST之類的簡單請求,也可以是PUT、DELETE等等。

Access-Control-Request-Headers – 該項是一個以逗號分隔的列表,當中是復雜請求所使用的頭部。

  顯而易見,這個預請求實際上就是在為之后的實際請求發送一個權限請求,在預回應返回的內容當中,服務端應當對這兩項進行回復,以讓瀏覽器確定請求是否能夠成功完成。

  復雜請求的部分響應頭及解釋如下:

Access-Control-Allow-Origin(必含) – 和簡單請求一樣的,必須包含一個域。

Access-Control-Allow-Methods(必含) – 這是對預請求當中Access-Control-Request-Method的回復,這一回復將是一個以逗號分隔的列表。盡管客戶端或許只請求某一方法,但服務端仍然可以返回所有允許的方法,以便客戶端將其緩存。

Access-Control-Allow-Headers(當預請求中包含Access-Control-Request-Headers時必須包含) – 這是對預請求當中Access-Control-Request-Headers的回復,和上面一樣是以逗號分隔的列表,可以返回所有支持的頭部。這里在實際使用中有遇到,所有支持的頭部一時可能不能完全寫出來,而又不想在這一層做過多的判斷,沒關系,事實上通過request的header可以直接取到Access-Control-Request-Headers,直接把對應的value設置到Access-Control-Allow-Headers即可。

Access-Control-Allow-Credentials(可選) – 和簡單請求當中作用相同 Access-Control-Max-Age(可選) – 以秒為單位的緩存時間。預請求的的發送並非免費午餐,允許時應當盡可能緩存。

  XMLHttpRequest會遵守同源策略(same-origin policy),也即腳本只能訪問相同協議、相同主機名、相同端口的資源,如果要突破這個限制,那就是所謂的跨域,此時需要遵守CORS(Cross-Origin Resource Sharing)機制。

  那么允許跨域,不就是服務端設置:Access-Control-Allow-Origin: *, 就可以了嗎? 普通的請求才是這樣子的, 除此之外,還一種叫請求叫preflighted request。

  preflighted request在發送真正的請求前, 會先發送一個方法為OPTIONS的預請求(preflight request), 用於試探服務端是否能接受真正的請求,如果options獲得的回應是拒絕性質的,比如404\403\500等http狀態,就會停止post、put等請求的發出。

  第一個OPTIONS的請求是由Web服務器處理跨域訪問引發的。OPTIONS是一種“預檢請求”,瀏覽器在處理跨域訪問的請求時如果判斷請求為復雜請求,則會先向服務器發送一條預檢請求,根據服務器返回的內容瀏覽器判斷服務器是否允許該請求訪問。如果web服務器采用cors的方式支持跨域訪問,在處理復雜請求時這個預檢請求是不可避免的。

三、簡單請求與復雜請求的跨域設置

  針對簡單請求,在進行CORS設置的時候,我們只需要設置

Access-Control-Allow-Origin:*
// 如果只是針對某一個請求源進行設置的話,可以設置為具體的值
Access-Control-Allow-Origin: 'http://www.***.com'

  針對復雜請求,我們需要設置不同的響應頭。因為在預檢請求的時候會攜帶相應的請求頭信息

Access-Control-Request-Method: POST Access-Control-Request-Headers: X-CUSTOMER-HEADER, Content-Type

  相應的響應頭信息為:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type // 設置max age,瀏覽器端會進行緩存。沒有過期之前真對同一個請求只會發送一次預檢請求
Access-Control-Max-Age: 86400

  如果發送的預檢請求被進行了重定向,那大多數的瀏覽器都不支持對預檢請求的重定向。我們可以通過先發送一個簡單請求的方式,獲取到重定向的url XHR.responseURL,然后再去請求這個url。

1、附帶身份憑證的請求

  一般而言,對於跨域 XMLHttpRequest或 Fetch 請求,瀏覽器不會發送身份憑證信息。如果要發送憑證信息,需要設置 XMLHttpRequest 的某個特殊標志位。

  如果在發送請求的時候,給xhr 設置了withCredentials為true,從而向服務器發送 Cookies,如果服務端需要想客戶端也發送cookie的情況,需要服務器端也返回Access-Control-Allow-Credentials: true 響應頭信息

  對於附帶身份憑證的請求,服務器不得設置 Access-Control-Allow-Origin的值為“*”。

  這是因為請求的首部中攜帶了Cookie信息,如果 Access-Control-Allow-Origin的值為“*”,請求將會失敗。而將 Access-Control-Allow-Origin的值設置為 http://foo.example(請求源),則請求將成功執行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM