Ajax 跨域(CORS)請求中的預檢請求

關於預檢請求

定義:預檢請求(Preflighted requests )是瀏覽器發起跨域請求時,經過OPTIONS方法詢問服務器對跨域請求的支持狀況(支持的包含請求方法、請求頭、數據類型)。html

觸發預檢請求的三類條件json

  1. 默認狀況下,跨域請求只支持GET,HEAD,POST方法,若是不是這三個請求方法(好比:PUT、DELETE、CONNECT、OPTIONS、TRACE和PATCH),那麼將觸發預檢請求跨域

  2. 默認狀況下,瀏覽器跨域請求時,會自動添加的請求頭(HOST,Referer,Connection、Accept、User-Agent,Accept-Languange,Accept-Encoding,Accept-Charset和Content-Type),這些請求中還有其餘請求頭時,那麼將觸發預檢請求。瀏覽器

  3. 如一、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

 

關於withCredentials

在跨域請求中,相似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請求

相關文章
相關標籤/搜索