首頁 >web前端 >html教學 >淺談關於預檢請求

淺談關於預檢請求

一个新手
一个新手原創
2017-09-18 10:24:314635瀏覽


淺談關於預檢請求

背景

不知道大家有沒有發現,有時候我們在呼叫後台介面的時候,會要求兩次,如下圖的

淺談關於預檢請求

其實第一次發送的就是preflight request(預檢請求),那麼這篇文章將講一下,為什麼要發預檢請求,什麼時候會發預檢請求,預檢請求都做了什麼

一. 為什麼要發預檢請求

#我們都知道瀏覽器的同源策略,就是出於安全考慮,瀏覽器會限制從腳本啟動的跨域HTTP請求,像XMLHttpRequest和Fetch都遵循同源策略。
瀏覽器限制跨域請求一般有兩種方式:
1. 瀏覽器限制發起跨域請求
2. 跨域請求可以正常發起,但是返回的結果被瀏覽器攔截了

一般瀏覽器都是第二種方式限制跨域請求,那就是說請求已到達伺服器,並有可能對資料庫裡的資料進行了操作,但是傳回的結果被瀏覽器攔截了,那麼我們就取得不到回傳結果,這是一個失敗的請求,但是可能對資料庫裡的資料產生了影響。

為了防止這種情況的發生,規範要求,對這種可能對伺服器資料產生副作用的HTTP請求方法,瀏覽器必須先使用OPTIONS方法發起一個預檢請求,從而獲知伺服器是否允許該跨域請求:如果允許,就發送帶資料的真實請求;如果不允許,則阻止發送帶資料的真實請求。

二. 何時發預檢請求

HTTP請求包含: 簡單請求與需預檢的請求

1.簡單請求

簡單請求不會觸發CORS預檢請求,「簡屬於
單一請求」術語並非屬於Fetch(其中定義了CORS)規範。
若符合所有下述條件,則該請求可視為「簡單請求」:
- 使用下列方法之一:
   - GET
   -  HEAD
   -  POST
       -  Content-Type: (僅當POST方法的Content-Type值等於下列之一才算做簡單需求)
             -    #text/plain
             -    multipart/form-data
-    application/x-www-form-urlencoded

注意: WebKit Nightly 和Safari Technology Preview 為Accept
, Accept-Language
, 和Content-Language
首部欄位的值增加了額外的限制。如果這些首部欄位的值是「非標準」的,WebKit/Safari 就不會將這些請求視為「簡單請求」。 WebKit/Safari 並沒有在文件中列出哪些值是「非標準」的,不過我們可以在這裡找到相關討論:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language, Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, and Switch to a blacklist model for restricted Accept headers in simple CORS requests。其它瀏覽器並不支援這些額外的限制,因為它們不屬於規範的一部分。

2.需預檢的請求

「需預檢的請求」要求必須先使用OPTIONS方法發起一個預檢請求到服務區,以獲知伺服器是否允許該實際請求。 「預檢請求」的使用,可以避免跨網域請求對伺服器的使用者資料產生未預期的影響。

當請求滿足下述任一條件時,即應先發送預檢請求:
- 使用了下面任一 HTTP 方法:
   - PUT
   - DELETE
   - CONNECT
   - OPTIONS
   - TRACE
   - PATCH
- 人為設定了 CORS 安全的首部欄位集合以外的其他首部欄位。該集合為:
 - Accept
#  - Accept-Language
 - Content-Language
 - Content-Type
 - DPR
#  - Downlink
#  - Save-Data
 - Viewport-Width
 - Width
#  - Content-Type
的值不屬於下列之一:      - application/x-www-form-urlencoded
     - multipart/form-data
     - text/plain

####

The following is an HTTP request that needs to perform a preflight request:

var invocation = new XMLHttpRequest();
var url = ' 
var body = &#39;<?xml version="1.0"?><person><name>Arun</name></person>&#39;;function callOtherDomain(){
  if(invocation)
    {
      invocation.open(&#39;POST&#39;, url, true);
      invocation.setRequestHeader(&#39;X-PRODUCT&#39;, &#39;H5&#39;);
      invocation.setRequestHeader(&#39;Content-Type&#39;, &#39;application/xml&#39;);
      invocation.onreadystatechange = handler;
      invocation.send(body); 
    }
}
......

The above code uses a POST request to send an XML document, which contains a custom header field (X-PRODUCT:H5) . In addition, the Content-Type of the request is application/xml. Therefore, the request needs to first initiate a "preflight request".
淺談關於預檢請求

1. OPTIONS /resources/post-here/ 
2. HTTP/1.13. Host: bar.other4. User-Agent: Mozilla/5.0 (Macintosh; U; 5.Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre6. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.87. Accept-Language: en-us,en;q=0.58. Accept-Encoding: gzip,deflate9. Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.710. Connection: keep-alive11. Origin: http://foo.example12. Access-Control-Request-Method: POST13. Access-Control-Request-Headers: X-PINGOTHER, Content-Type14. HTTP/1.1 200 OK15. Date: Mon, 01 Dec 2008 01:15:39 GMT16. Server: Apache/2.0.61 (Unix)17. Access-Control-Allow-Origin: http://foo.example18. Access-Control-Allow-Methods: POST, GET, OPTIONS19. Access-Control-Allow-Headers: X-PINGOTHER, Content-Type20. Access-Control-Max-Age: 8640021. Vary: Accept-Encoding, Origin22. Content-Encoding: gzip23. Content-Length: 024. Keep-Alive: timeout=2, max=10025. Connection: Keep-Alive26. Content-Type: text/plain

As you can see from the above message, lines 1 to 12 send a preflight request using the OPTIONS method. OPTIONS is a method defined in the HTTP/1.1 protocol to obtain more information from the server. This method has no impact on server resources. The request carries the following two header fields at the same time:

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PRODUCT

The header field Access-Control-Request-Method tells the server that the actual request will use the POST method. The header field Access-Control-Request-Headers tells the server that the actual request will carry two custom request header fields: X-PINGOTHER and Content-Type. The server decides based on this whether the actual request is allowed.

Lines 14 to 26 are responses to preflight requests, indicating that the server will stick to subsequent actual requests. Focus on lines 17~20:

Access-Control-Allow-Origin: http://foo.exampleAccess-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-TypeAccess-Control-Max-Age: 86400

The header field Access-Control-Allow-Methods indicates that the server allows the client to use the POST, GET and OPTIONS methods to initiate requests.

The header fieldAccess-Control-Allow-Headers indicates that the server allows the fields X-PINGOTHER and Content-Type to be carried in the request. Like Access-Control-Allow-Methods, the value of Access-Control-Allow-Headers is a comma-separated list.

Finally, the header field

Access-Control-Max-Age indicates that the response is valid for 86400 seconds, which is 24 hours. Within the validity period, the browser does not need to initiate a preflight request again for the same request. Please note that the browser itself maintains a maximum validity time. If the value of this header field exceeds the maximum validity time, it will not take effect.

After the preflight request is completed, send the actual request:

POST /resources/post-here/ HTTP/1.1Host: bar.otherUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3preAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip,deflateAccept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7Connection: keep-aliveX-PINGOTHER: pingpongContent-Type: text/xml; charset=UTF-8Referer: http://foo.example/examples/preflightInvocation.htmlContent-Length: 55Origin: http://foo.examplePragma: no-cacheCache-Control: no-cache<?xml version="1.0"?><person><name>Arun</name></person>HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain
[Some GZIP&#39;d payload]

以上是淺談關於預檢請求的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn