AJAX(XMLHttpRequest)進行跨域請求方法詳解(二)

孟子E章發表於2010-01-11
2,預檢請求

預檢請求首先需要向另外一個域名的資源傳送一個 HTTP OPTIONS 請求頭,其目的就是為了判斷實際傳送的請求是否是安全的。下面的2種情況需要進行預檢:
a,不是上面的簡單請求,比如使用Content-Type 為 application/xml 或 text/xml 的 POST 請求
b,在請求中設定自定義頭,比如 X-JSON、X-MENGXIANHUI 等


注意:在 iis 裡進行測試,必須在“應用程式擴充套件”裡面配置 .aspx 擴充套件的動作允許 OPTIONS。

下面我們舉一個預檢的請求:

br>  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


孟憲會之AJAX跨域請求測試


 
 

 
  //  var xhr = new XMLHttpRequest();
  var url = 'http://dotnet.aspx.cc/PreflightedRequests.aspx';
  function crossDomainRequest() {
    document.getElementById("content").innerHTML = "開始進行請求……";
    if (xhr) {
      var xml = "測試";
      xhr.open('POST', url, true);
      xhr.setRequestHeader("POWERED-BY-MENGXIANHUI", "Approve");
      xhr.setRequestHeader("Content-Type", "application/xml");
      xhr.onreadystatechange = handler;
      xhr.send(xml);
    } else {
    document.getElementById("content").innerHTML = "不能建立 XMLHttpRequest。";
    }
  }
  function handler(evtXHR) {
    if (xhr.readyState == 4) {
      if (xhr.status == 200) {
        var response = xhr.responseText;
        document.getElementById("content").innerHTML = "結果:" + response;
      } else {
        document.getElementById("content").innerHTML = "不能進行跨越訪問。";
      }
    }
    else {
      document.getElementById("content").innerHTML += "
執行狀態 readyState:" + xhr.readyState;
    }
  }
  //]]>





上面的例子我們傳送 xml 格式的資料,並且,傳送一個非標準的HTTP頭 POWERED-BY-MENGXIANHUI 來說明伺服器端該如何設定響應頭的。

在伺服器端,PreflightedRequests.aspx 的內容如下:



  protected void Page_Load(object sender, EventArgs e)
  {
    if (Request.HttpMethod.Equals("GET"))
    {      
      Response.Write("這個頁面是用來測試跨域 POST 請求的,直接瀏覽意義不大。");
    }
    else if (Request.HttpMethod.Equals("OPTIONS"))
    {
      //通知客戶端允許預檢請求。並設定快取時間
      Response.ClearContent();
      Response.AddHeader("Access-Control-Allow-Origin", "http://www.meng_xian_hui.com:801");
      Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
      Response.AddHeader("Access-Control-Allow-Headers", "POWERED-BY-MENGXIANHUI");
      Response.AddHeader("Access-Control-Max-Age", "30");  
      //此過程無需返回資料
      Response.End();      
    }
    else if (Request.HttpMethod.Equals("POST"))
    {
      if (Request.Headers["Origin"].Equals("http://www.meng_xian_hui.com:801"))
      {
        System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
        doc.Load(Request.InputStream);
        Response.AddHeader("Access-Control-Allow-Origin", "http://www.meng_xian_hui.com:801");
        Response.Write("您提交的資料是:

" + Server.HtmlEncode(doc.OuterXml));
      }
      else
      {
        Response.Write("不允許你的網站請求。");
      }
    }
  }




點選“開始測試”按鈕,將會執行下面的一系列請求。

OPTIONS /PreflightedRequests.aspx HTTP/1.1
Host: dotnet.aspx.cc
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Origin: http://www.meng_xian_hui.com:801
Access-Control-Request-Method: POST
Access-Control-Request-Headers: powered-by-mengxianhui

HTTP/1.x 200 OK
Date: Sun, 10 Jan 2010 14:00:34 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Access-Control-Allow-Origin: http://www.meng_xian_hui.com:801
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: POWERED-BY-MENGXIANHUI
Access-Control-Max-Age: 30
Set-Cookie: ASP.NET_SessionId=5npqri55dl1k1zvij1tlw3re; path=/; HttpOnly
Cache-Control: private
Content-Length: 0

POST /PreflightedRequests.aspx HTTP/1.1
Host: dotnet.aspx.cc
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
POWERED-BY-MENGXIANHUI: Approve
Content-Type: application/xml; charset=UTF-8
Referer: http://www.meng_xian_hui.com:801/CrossDomainAjax/PreflightedRequests.html
Content-Length: 19
Origin: http://www.meng_xian_hui.com:801
Pragma: no-cache
Cache-Control: no-cache
測試

HTTP/1.x 200 OK
Date: Sun, 10 Jan 2010 14:00:34 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Access-Control-Allow-Origin: http://www.meng_xian_hui.com:801
Set-Cookie: ASP.NET_SessionId=byvose45zmtbqy45d2a1jf2i; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 65


以上的程式碼反映了預檢請求的執行過程:首先傳送 OPTIONS 請求頭,用來向伺服器諮詢伺服器的更多資訊,以便為後續的真實請求做準備。比如是否支援 POST 方法等。值得注意的是:

瀏覽器還傳送 Access-Control-Request-Method: POST 和 Access-Control-Request-Headers: powered-by-mengxianhui 請求頭。

注意:以上過程是第一次請求的時候的過程,如果在 30 秒內重複點選按鈕,你可以看不到 OPTIONS 這一過程。則執行過程是這樣的:

POST /PreflightedRequests.aspx HTTP/1.1
Host: dotnet.aspx.cc
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.2; zh-CN; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7 (.NET CLR 3.5.30729)
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
POWERED-BY-MENGXIANHUI: Approve
Content-Type: application/xml; charset=UTF-8
Referer: http://www.meng_xian_hui.com:801/CrossDomainAjax/PreflightedRequests.html
Content-Length: 19
Origin: http://www.meng_xian_hui.com:801
Pragma: no-cache
Cache-Control: no-cache
測試

HTTP/1.x 200 OK
Date: Sun, 10 Jan 2010 14:06:32 GMT
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50727
Access-Control-Allow-Origin: http://www.meng_xian_hui.com:801
Set-Cookie: ASP.NET_SessionId=qs1c4urxywdbdx55u04pvual; path=/; HttpOnly
Cache-Control: private
Content-Type: text/html; charset=utf-8
Content-Length: 65

為什麼會這樣?細心的童鞋可能注意到了,在伺服器端有一行程式碼 Response.AddHeader("Access-Control-Max-Age", "30");  它是用來設定預檢的有效時間的,單位是秒。這一點要特別注意。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15723462/viewspace-624783/,如需轉載,請註明出處,否則將追究法律責任。

相關文章