AJAX(XMLHttpRequest)進行跨域要求方法詳解(一)

來源:互聯網
上載者:User

注意:以下代碼請在Firefox 3.5、Chrome 3.0、Safari 4之後的版本中進行測試。IE8的實現方法與其他瀏覽不同。

跨域請求,顧名思義,就是一個網站中的資源去訪問另外一個不同網域名稱網站上的資源。這種情況很常見,比如說通過 style 標籤載入外部樣式表檔案、通過 img 標籤載入外部圖片、通過 script 標籤載入外部指令檔、通過 Webfont 載入字型檔等等。預設情況下,指令碼訪問文件屬性等資料採用的是同源策略(Same origin policy)。

那麼,什麼是同源策略呢?如果兩個頁面的協議、網域名稱和連接埠是完全相同的,那麼它們就是同源的。同源策略是為了防止從一個地址載入的文檔或指令碼訪問或者設定從另外一個地址載入的文檔的屬性。如果兩個頁面的主網域名稱相同,則還可以通過設定 document.domain 屬性將它們認為是同源的。

隨著 Web2.0 和 SNS 的興起,Web 應用程式對跨域訪問的需求也越來越多,但是,在指令碼中進行跨域請求是受安全性限制的,Web 開發人員迫切需要提供一種更安全、方便的跨域請求方式來融合(Mashup)自己的 Web 應用程式。這樣做的一個好處就是可以將請求分攤到不同的伺服器,減輕單個伺服器壓力以提高響應速度;另外一個好處是可以將不同的商務邏輯分布到不同的伺服器上以降低負載。

值得慶幸的是,跨域請求的標準已經出台,主流瀏覽器也已經實現了這一標準。W3C 工作群組中的 Web Applications Working Group(Web 應用程式工作群組)發布了一個 Cross-Origin Resource Sharing(跨域資源共用,該規範地址:http://www.w3.org/TR/access-control/和http://dev.w3.org/2006/waf/access-control/) 推薦規範來解決跨域請求的問題。該規範提供了一種更安全的跨域資料交換方法。具體規範的介紹可以訪問上面提供的網站地址。值得注意的是:該規範只能應用在類似 XMLHttprequest 這樣的 API 容器內。IE8、Firefox 3.5 及其以後的版本、Chrome瀏覽器、Safari 4 等已經實現了 Cross-Origin Resource Sharing 規範,已經可以進行跨域請求了。

Cross-Origin Resource Sharing 的工作方式是通過添加 HTTP 頭的方法來判斷哪些資源允許 網頁瀏覽器訪問該網域名稱下的資訊。然而,對於那些 HTTP 要求導致使用者資料產生副作用的要求方法(特別是對於除了GET、某些 MIME 類型的 POST 之外的 HTTP方法),該規範要求瀏覽器對請求進行“預先驗”,通過發送 HTTP 的 OPTIONS 要求標頭詢問伺服器有哪些支援的方法,在徵得伺服器的同意後,再使用實際的 HTTP 要求方法發送實際的請求。伺服器也可以通知用戶端是否需要將驗證資訊(如 Cookie 和 HTTP Authentication 資料)隨同請求一起發送。

下面我們就採用實際的例子說明 Cross-Origin Resource Sharing 是如何工作的。

 

1,簡單請求

 

什麼樣的請求算是簡單請求呢?簡單請求必須滿足下面2點:

a,只使用 GET、POST 進行的請求,這裡的POST只包括髮送給伺服器的資料類型(Content-Type)必須是 application/x-www-form-urlencoded、multipart/form-data 或者 text/plain中一個。

b,HTTP 要求沒有設定自訂的要求標頭,如我們常用的 X-JSON。

 

先使用下面的代碼進行測試:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<br /> "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html xmlns="http://www.w3.org/1999/xhtml"><br /><head><br /> <title>孟憲會之AJAX跨域請求測試</title><br /></head><br /><body><br /> <input type='button' value='開始測試' onclick='crossDomainRequest()' /><br /> <div id="content"></div><br /> <mce:script type="text/javascript"><!--<br /> var xhr = new XMLHttpRequest();<br /> var url = 'http://dotnet.aspx.cc/SimpleCrossSiteRequests.aspx';<br /> function crossDomainRequest() {<br /> document.getElementById("content").innerHTML = "開始……";<br /> if (xhr) {<br /> xhr.open('GET', url, true);<br /> xhr.onreadystatechange = handler;<br /> xhr.send();<br /> } else {<br /> document.getElementById("content").innerHTML = "不能建立 XMLHttpRequest";<br /> }<br /> }<br /> function handler(evtXHR) {<br /> if (xhr.readyState == 4) {<br /> if (xhr.status == 200) {<br /> var response = xhr.responseText;<br /> document.getElementById("content").innerHTML = "結果:" + response;<br /> } else {<br /> document.getElementById("content").innerHTML = "不允許跨域請求。";<br /> }<br /> }<br /> else {<br /> document.getElementById("content").innerHTML += "<br/>執行狀態 readyState:" + xhr.readyState;<br /> }<br /> }<br />// --></mce:script><br /></body><br /></html>

 

然後,在伺服器建立 CrossDomainRequest.aspx 的內容如下:

<%@ Page Language="C#" %><br /><mce:script runat="server"><!--<br /> protected void Page_Load(object sender, EventArgs e)<br /> {<br /> Response.AddHeader("Access-Control-Allow-Origin", "http://www.meng_xian_hui.com:801");<br /> Response.Write("孟憲會向各位朋友發來賀電:你的第一個跨域測試成功啦!!!");<br /> }<br />// --></mce:script>

 

點擊 “開始測試” 按鈕,發送的請求和返回的響應資訊如下:

 

GET /SimpleCrossSiteRequests.aspx HTTP/1.1<br />Host: dotnet.aspx.cc<br />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)<br />Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br />Accept-Language: zh-cn,zh;q=0.5<br />Accept-Encoding: gzip,deflate<br />Accept-Charset: GB2312,utf-8;q=0.7,*;q=0.7<br />Keep-Alive: 300<br />Connection: keep-alive<br />Referer: http://www.meng_xian_hui.com:801/CrossDomainAjax/SimpleCrossSiteRequests.html<br />Origin: http://www.meng_xian_hui.com:801<br />HTTP/1.x 200 OK<br />Date: Sun, 10 Jan 2010 13:52:00 GMT<br />Server: Microsoft-IIS/6.0<br />X-Powered-By: ASP.NET<br />X-AspNet-Version: 2.0.50727<br />Access-Control-Allow-Origin: http://www.meng_xian_hui.com:801<br />Set-Cookie: ASP.NET_SessionId=wk5v5nrs5wbfi4rmpjy2jujb; path=/; HttpOnly<br />Cache-Control: private<br />Content-Type: text/html; charset=utf-8<br />Content-Length: 84

需要特別注意的是:在請求資訊中,瀏覽器使用 Origin 這個 HTTP 頭來標識該請求來自於 http://www.meng_xian_hui.com:801;在返回的響應資訊中,使用 Access-Control-Allow-Origin 頭來控制哪些網域名稱的指令碼可以訪問該資源。如果設定 Access-Control-Allow-Origin:*,則允許所有網域名稱的指令碼訪問該資源。如果有多個,則只需要使用逗號分隔開即可。

注意:在伺服器端,Access-Control-Allow-Origin 回應標頭 http://www.meng_xian_hui.com:801 中的連接埠資訊不能省略。

有人可能會想:自己發送要求標頭會如何呢?比如 xhr.setRequestHeader("Origin","http://www.meng_xian_hui.com:801"); 實踐證明,自己設定 Origin 頭是不行的。

是不是現在就可以採用 XMLHttpRequest 來請求任意一個網站的資料呢?還是不行的。允許哪些網域名稱可以訪問,還需要伺服器來設定 Access-Control-Allow-Origin 頭來進行授權,具體的代碼是:

Response.AddHeader("Access-Control-Allow-Origin", "http://www.meng_xian_hui.com:801");

這行代碼就告訴瀏覽器,只有來自 http://www.meng_xian_hui.com:801 源下的指令碼才可以進行訪問。

好了,上面我們就完成了一個簡單的跨域請求,怎麼樣?感覺還是不錯的吧。下面我們進行一個“預檢”請求。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.