定義:預檢請求(Preflighted requests )是瀏覽器發起跨域請求時,經過OPTIONS方法詢問服務器對跨域請求的支持狀況(支持的包含請求方法、請求頭、數據類型)。html
觸發預檢請求的三類條件:json
默認狀況下,跨域請求只支持GET,HEAD,POST方法,若是不是這三個請求方法(好比:PUT、DELETE、CONNECT、OPTIONS、TRACE和PATCH),那麼將觸發預檢請求跨域
默認狀況下,瀏覽器跨域請求時,會自動添加的請求頭(HOST,Referer,Connection、Accept、User-Agent,Accept-Languange,Accept-Encoding,Accept-Charset和Content-Type),這些請求中還有其餘請求頭時,那麼將觸發預檢請求。瀏覽器
如一、2所說的狀況排除在外的條件下,跨域請求是,瀏覽器支持的Content-Type值爲application/x-www-form-urlencoded,multipart/form-data和text/plain。若是是其餘數據類型(如application/json,text/xml...),那麼將觸發預檢請求。緩存
下面經過一個Ajax跨域請求來驗證服務器
var xhr= new XMLHttpRequest(); var url = 'http://bar.other/resources/post-here/'; var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; function callOtherDomain(){ if(invocation) { xhr.open('POST', url, true); xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); //自定義的Header xhr.setRequestHeader('Content-Type', 'application/xml'); //特殊的文檔類型 xhr.onreadystatechange = function(){}; xhr.send(body); } }
知足以上之一,即可發起預檢請求,預檢請求流程以下cookie
OPTIONS /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: http://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400 Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain POST /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: http://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: http://foo.example Pragma: no-cache Cache-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'd payload]
咱們看到,首次發起的是OPTIONS請求,由於OPTIONS請求的做用自己就是詢問服務器的請求,他這裏詢問瀏覽器是否支持以下條件請求app
Access-Control-Request-Method: POST #是否支持POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type #是否支持X-PINGOTHER自定義請求頭的內容,Content-Type多是其餘值,所以有必要詢問
服務器迴應是post
Access-Control-Allow-Origin: http://foo.example #支持foo.example域 Access-Control-Allow-Methods: POST, GET, OPTIONS #支持的方法POST,GET,OPTIONS,實際上OPTIONS自己就支持 Access-Control-Allow-Headers: X-PINGOTHER, Content-Type #支持的請求頭,Content-Type是特殊的類型時,會觸發預檢,所以,這裏最好加上Content-Type Access-Control-Max-Age: 86400 #支持的緩存時間
若是知足以上條件,瀏覽器會自動發起提交以前沒提交的數據,不然拒絕提交數據。url
在跨域請求中,相似Cookie等敏感信息通常不會跨域傳輸,可是在服務器容許的狀況下,Cookie會被髮送
注意:Cookie的發送須要服務器容許才行,此外,跨域js所處的環境必須是線上環境【服務器環境】。
Access-Control-Allow-Credentials: true
瀏覽器也要容許
var xhr= new XMLHttpRequest(); var url = 'http://bar.other/resources/post-here/'; var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; function callOtherDomain(){ if(invocation) { xhr.withCredentials = true;#容許cookie信息 xhr.open('POST', url, true); xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); //自定義的Header xhr.setRequestHeader('Content-Type', 'application/xml'); //特殊的文檔類型 xhr.onreadystatechange = function(){}; xhr.send(body); } }
服務器設計,咱們不只要處理常見的跨域請求,對於Preflighted Request請求,咱們更應該保證瀏覽器能獲得預檢請求的結果,所以,服務器端必定要處理OPTIONS請求