XMLHttpRequest Level 2 使用指南
http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.html
?
XMLHttpRequest是一個瀏覽器接口,使得Javascript可以進(jìn)行HTTP(S)通信。
最早,微軟在IE 5引進(jìn)了這個接口。因為它太有用,其他瀏覽器也模仿部署了,ajax操作因此得以誕生。
但是,這個接口一直沒有標(biāo)準(zhǔn)化,每家瀏覽器的實現(xiàn)或多或少有點不同。HTML 5的概念形成后,W3C開始考慮標(biāo)準(zhǔn)化這個接口。2008年2月,就提出了XMLHttpRequest Level 2?草案。
這個XMLHttpRequest的新版本,提出了很多有用的新功能,將大大推動互聯(lián)網(wǎng)革新。本文就對這個新版本進(jìn)行詳細(xì)介紹。
一、老版本的XMLHttpRequest對象
在介紹新版本之前,我們先回顧一下老版本的用法。
首先,新建一個XMLHttpRequest的實例。
var xhr = new XMLHttpRequest();
然后,向遠(yuǎn)程主機(jī)發(fā)出一個HTTP請求。
xhr.open('GET', 'example.php');
xhr.send();
接著,就等待遠(yuǎn)程主機(jī)做出回應(yīng)。這時需要監(jiān)控XMLHttpRequest對象的狀態(tài)變化,指定回調(diào)函數(shù)。
xhr.onreadystatechange = function(){
if ( xhr.readyState == 4 && xhr.status == 200 ) {
alert( xhr.responseText );
} else {
alert( xhr.statusText );
}
};
上面的代碼包含了老版本XMLHttpRequest對象的主要屬性:
* xhr.readyState:XMLHttpRequest對象的狀態(tài),等于4表示數(shù)據(jù)已經(jīng)接收完畢。
* xhr.status:服務(wù)器返回的狀態(tài)碼,等于200表示一切正常。
* xhr.responseText:服務(wù)器返回的文本數(shù)據(jù)
* xhr.responseXML:服務(wù)器返回的XML格式的數(shù)據(jù)
* xhr.statusText:服務(wù)器返回的狀態(tài)文本。
二、老版本的缺點
老版本的XMLHttpRequest對象有以下幾個缺點:
* 只支持文本數(shù)據(jù)的傳送,無法用來讀取和上傳二進(jìn)制文件。
* 傳送和接收數(shù)據(jù)時,沒有進(jìn)度信息,只能提示有沒有完成。
* 受到"同域限制"(Same Origin Policy),只能向同一域名的服務(wù)器請求數(shù)據(jù)。
三、新版本的功能
新版本的XMLHttpRequest對象,針對老版本的缺點,做出了大幅改進(jìn)。
* 可以設(shè)置HTTP請求的時限。
* 可以使用FormData對象管理表單數(shù)據(jù)。
* 可以上傳文件。
* 可以請求不同域名下的數(shù)據(jù)(跨域請求)。
* 可以獲取服務(wù)器端的二進(jìn)制數(shù)據(jù)。
* 可以獲得數(shù)據(jù)傳輸?shù)倪M(jìn)度信息。
下面,我就一一介紹這些新功能。
四、HTTP請求的時限
有時,ajax操作很耗時,而且無法預(yù)知要花多少時間。如果網(wǎng)速很慢,用戶可能要等很久。
新版本的XMLHttpRequest對象,增加了timeout屬性,可以設(shè)置HTTP請求的時限。
xhr.timeout = 3000;
上面的語句,將最長等待時間設(shè)為3000毫秒。過了這個時限,就自動停止HTTP請求。與之配套的還有一個timeout事件,用來指定回調(diào)函數(shù)。
xhr.ontimeout = function(event){
alert('請求超時!');
}
目前,Opera、Firefox和IE 10支持該屬性,IE 8和IE 9的這個屬性屬于XDomainRequest對象,而Chrome和Safari還不支持。
五、FormData對象
ajax操作往往用來傳遞表單數(shù)據(jù)。為了方便表單處理,HTML 5新增了一個FormData對象,可以模擬表單。
首先,新建一個FormData對象。
var formData = new FormData();
然后,為它添加表單項。
formData.append('username', '張三');
formData.append('id', 123456);
最后,直接傳送這個FormData對象。這與提交網(wǎng)頁表單的效果,完全一樣。
xhr.send(formData);
FormData對象也可以用來獲取網(wǎng)頁表單的值。
var form = document.getElementById('myform');
var formData = new FormData(form);
formData.append('secret', '123456'); // 添加一個表單項
xhr.open('POST', form.action);
xhr.send(formData);
六、上傳文件
新版XMLHttpRequest對象,不僅可以發(fā)送文本信息,還可以上傳文件。
假定files是一個"選擇文件"的表單元素(input[type="file"]),我們將它裝入FormData對象。
var formData = new FormData();
for (var i = 0; i < files.length;i++) {
formData.append('files[]', files[i]);
}
然后,發(fā)送這個FormData對象。
xhr.send(formData);
七、跨域資源共享(CORS)
新版本的XMLHttpRequest對象,可以向不同域名的服務(wù)器發(fā)出HTTP請求。這叫做"跨域資源共享"(Cross-origin resource sharing,簡稱CORS)。
使用"跨域資源共享"的前提,是瀏覽器必須支持這個功能,而且服務(wù)器端必須同意這種"跨域"。如果能夠滿足上面的條件,則代碼的寫法與不跨域的請求完全一樣。
xhr.open('GET', 'http://other.server/and/path/to/script');
目前,除了IE 8和IE 9,主流瀏覽器都支持CORS,IE 10也將支持這個功能。服務(wù)器端的設(shè)置,請參考《Server-Side Access Control》。
八、接收二進(jìn)制數(shù)據(jù)(方法A:改寫MIMEType)
老版本的XMLHttpRequest對象,只能從服務(wù)器取回文本數(shù)據(jù)(否則它的名字就不用XML起首了),新版則可以取回二進(jìn)制數(shù)據(jù)。
這里又分成兩種做法。較老的做法是改寫數(shù)據(jù)的MIMEType,將服務(wù)器返回的二進(jìn)制數(shù)據(jù)偽裝成文本數(shù)據(jù),并且告訴瀏覽器這是用戶自定義的字符集。
xhr.overrideMimeType("text/plain; charset=x-user-defined");
然后,用responseText屬性接收服務(wù)器返回的二進(jìn)制數(shù)據(jù)。
var binStr = xhr.responseText;
由于這時,瀏覽器把它當(dāng)做文本數(shù)據(jù),所以還必須再一個個字節(jié)地還原成二進(jìn)制數(shù)據(jù)。
for (var i = 0, len = binStr.length; i < len; ++i) {
var c = binStr.charCodeAt(i);
var byte = c & 0xff;
}
最后一行的位運算"c & 0xff",表示在每個字符的兩個字節(jié)之中,只保留后一個字節(jié),將前一個字節(jié)扔掉。原因是瀏覽器解讀字符的時候,會把字符自動解讀成Unicode的0xF700-0xF7ff區(qū)段。
八、接收二進(jìn)制數(shù)據(jù)(方法B:responseType屬性)
從服務(wù)器取回二進(jìn)制數(shù)據(jù),較新的方法是使用新增的responseType屬性。如果服務(wù)器返回文本數(shù)據(jù),這個屬性的值是"TEXT",這是默認(rèn)值。較新的瀏覽器還支持其他值,也就是說,可以接收其他格式的數(shù)據(jù)。
你可以把responseType設(shè)為blob,表示服務(wù)器傳回的是二進(jìn)制對象。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png');
xhr.responseType = 'blob';
接收數(shù)據(jù)的時候,用瀏覽器自帶的Blob對象即可。
var blob = new Blob([xhr.response], {type: 'image/png'});
注意,是讀取xhr.response,而不是xhr.responseText。
你還可以將responseType設(shè)為arraybuffer,把二進(jìn)制數(shù)據(jù)裝在一個數(shù)組里。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png');
xhr.responseType = "arraybuffer";
接收數(shù)據(jù)的時候,需要遍歷這個數(shù)組。
var arrayBuffer = xhr.response;
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteArray.byteLength; i++) {
// do something
}
}
更詳細(xì)的討論,請看Sending and Receiving Binary Data。
九、進(jìn)度信息
新版本的XMLHttpRequest對象,傳送數(shù)據(jù)的時候,有一個progress事件,用來返回進(jìn)度信息。
它分成上傳和下載兩種情況。下載的progress事件屬于XMLHttpRequest對象,上傳的progress事件屬于XMLHttpRequest.upload對象。
我們先定義progress事件的回調(diào)函數(shù)。
xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
然后,在回調(diào)函數(shù)里面,使用這個事件的一些屬性。
function updateProgress(event) {
if (event.lengthComputable) {
var percentComplete = event.loaded / event.total;
}
}
上面的代碼中,event.total是需要傳輸?shù)目傋止?jié),event.loaded是已經(jīng)傳輸?shù)淖止?jié)。如果event.lengthComputable不為真,則event.total等于0。
與progress事件相關(guān)的,還有其他五個事件,可以分別指定回調(diào)函數(shù):
* load事件:傳輸成功完成。
* abort事件:傳輸被用戶取消。
* error事件:傳輸中出現(xiàn)錯誤。
* loadstart事件:傳輸開始。
* loadEnd事件:傳輸結(jié)束,但是不知道成功還是失敗。
十、閱讀材料
1.?Introduction to XMLHttpRequest Level 2: 新功能的綜合介紹。
2.?New Tricks in XMLHttpRequest 2:一些用法的介紹。
3.?Using XMLHttpRequest:一些高級用法,主要針對Firefox瀏覽器。
4.?HTTP Access Control:CORS綜述。
5.?DOM access control using cross-origin resource sharing:CORS的9種HTTP頭信息
6.?Server-Side Access Control:服務(wù)器端CORS設(shè)置。
7.?Enable CORS:服務(wù)端CORS設(shè)置。
(完)
文檔信息
- 版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(創(chuàng)意共享3.0許可證)
- 發(fā)表日期:?2012年9月 8日
- 更多內(nèi)容:?檔案???JavaScript
- 文集:《前方的路》,《未來世界的幸存者》
- 社交媒體:?twitter,?weibo
相關(guān)文章
- 2018.03.20:?Node 調(diào)試工具入門教程 JavaScript 程序越來越復(fù)雜,調(diào)試工具的重要性日益凸顯。客戶端腳本有瀏覽器,Node 腳本怎么調(diào)試呢?
- 2018.02.23:?Node 定時器詳解 JavaScript 是單線程運行,異步操作特別重要。
- 2017.09.19:?《ES6 標(biāo)準(zhǔn)入門(第3版)》上市了! 2017年6月,TC39 委員會正式發(fā)布了《ES2017 標(biāo)準(zhǔn)》。
- 2017.09.07:?asm.js 和 Emscripten 入門教程 Web 技術(shù)突飛猛進(jìn),但是有一個領(lǐng)域一直無法突破 ---- 游戲。
廣告(購買廣告位)
留言(31條)
學(xué)習(xí)了,html5的新特性真讓人著迷
2012年9月 9日 10:21?|?#?|?引用
其實IE8,9也支持跨域資源共享,不過用的是 XDomainRequest 對象,而且做法和w3c標(biāo)準(zhǔn)不同,不是設(shè)置在header里而是要放一個文件在服務(wù)器上(類似Flash跨域的做法)。
2012年9月 9日 23:21?|?#?|?引用
引用RedNax的發(fā)言:
其實IE8,9也支持跨域資源共享,不過用的是 XDomainRequest 對象,而且做法和w3c標(biāo)準(zhǔn)不同,不是設(shè)置在header里而是要放一個文件在服務(wù)器上(類似Flash跨域的做法)。
IE8,9也支持跨域沒有錯,可用接口單一,但是并不需要放一個文件在服務(wù)器上,也不類似flash。
我做過測試:?http://cssor.com/cross-origin-resource-sharing.html
2012年9月10日 10:59?|?#?|?引用
剛看了《黑客與畫家》,確實是一本不可多得的好書!
2012年9月10日 20:41?|?#?|?引用
引用ToFishes的發(fā)言:
?
IE8,9也支持跨域沒有錯,可用接口單一,但是并不需要放一個文件在服務(wù)器上,也不類似flash。
我做過測試:?http://cssor.com/cross-origin-resource-sharing.html
哦,看了一下文檔確實如此。看來是我和什么混起來了……2012年9月10日 20:51?|?#?|?引用
Websocket比xhr更強(qiáng)大,可以實現(xiàn)實時的push,現(xiàn)在只能靠flash,隨著支持瀏覽器的普及,將會看到更多用websocket的網(wǎng)站,阮先生也可以介紹一下
2012年9月11日 11:24?|?#?|?引用
最近的內(nèi)容涉及到好多技術(shù)的細(xì)節(jié)問題,沒有太大的興趣,當(dāng)然了,寫什么是阮兄的自由。
2012年9月12日 05:20?|?#?|?引用
js跨域還在研究當(dāng)中,學(xué)習(xí)啦
2012年9月24日 16:37?|?#?|?引用
不錯,假如可以順便知道支持的瀏覽器的大致版本號就好了。
2012年10月 2日 15:54?|?#?|?引用
據(jù)我了解文中提到的“跨域資源共享(CORS)”目前還是w3c的草案,還沒有正式發(fā)布。
2012年11月22日 17:22?|?#?|?引用
博主,關(guān)于CORS,最好再加上Preflighted request的內(nèi)容
如果要使用除GET和POST以外的方法,或者想用content-type不是application/x-www-form-urlencoded, multipart/form-data, or text/plain 的POST,需要在request的header中添加額外的custom header
Preflighted requests
Unlike simple requests (discussed above), "preflighted" requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:
It uses methods other than GET or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)
https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#Preflighted_requests
http://arunranga.com/examples/access-control/preflightInvocation.html
2013年2月 6日 14:32?|?#?|?引用
這里有不少的Demo可以參考:http://tiffanybbrown.com/presentation/2011/xhr2/
2013年2月20日 08:55?|?#?|?引用
樓主您好,請問您本人是否試過XMLHttpRequest上傳文件?如果有,請指教,最好是您完整的JS代碼,我無惡意,通過實踐之后只是對XMLHttpRequest上傳文件表示質(zhì)疑。畢竟他歸根結(jié)底還是一個AJAX,歡迎QQ或是郵件交流和指點,謝謝O(∩_∩)O.qq:303834036
2013年3月17日 18:37?|?#?|?引用
正在學(xué)習(xí)跨文檔通信 謝謝樓主的資料0w0
2013年4月16日 21:08?|?#?|?引用
引用jalorchen的發(fā)言:
樓主您好,請問您本人是否試過XMLHttpRequest上傳文件?如果有,請指教,最好是您完整的JS代碼,我無惡意,通過實踐之后只是對XMLHttpRequest上傳文件表示質(zhì)疑。畢竟他歸根結(jié)底還是一個AJAX,歡迎QQ或是郵件交流和指點,謝謝O(∩_∩)O.qq:303834036
說到底,就是http協(xié)議,當(dāng)然可以上傳文件。 利用formdata上傳過文件,將頭信息更改為application/multiple,請求信息中還需要加入boundary信息,后臺就可以進(jìn)行解析了。后臺用第三方組件解析要方便一些,我用的就是java的commonupload組件。2014年3月17日 14:05?|?#?|?引用
引用dirty的發(fā)言:
Websocket比xhr更強(qiáng)大,可以實現(xiàn)實時的push,現(xiàn)在只能靠flash,隨著支持瀏覽器的普及,將會看到更多用websocket的網(wǎng)站,阮先生也可以介紹一下
是呀,阮老師可以介紹一下web socket.
2014年4月11日 19:48?|?#?|?引用
引用dirty的發(fā)言:
Websocket比xhr更強(qiáng)大,可以實現(xiàn)實時的push,現(xiàn)在只能靠flash,隨著支持瀏覽器的普及,將會看到更多用websocket的網(wǎng)站,阮先生也可以介紹一下
Flash的錯在于它只是一個插件,小三永遠(yuǎn)轉(zhuǎn)不了正。我下載新版firefox后,一啟動就提示Flash崩潰,用戶遇到這種情況怎么跟他解析?!
2014年10月17日 23:51?|?#?|?引用
chrome 38.0已經(jīng)支持xhr的timeout了
2014年11月 3日 13:53?|?#?|?引用
引用Thyiad的發(fā)言:
說到底,就是http協(xié)議,當(dāng)然可以上傳文件。
利用formdata上傳過文件,將頭信息更改為application/multiple,請求信息中還需要加入boundary信息,后臺就可以進(jìn)行解析了。后臺用第三方組件解析要方便一些,我用的就是java的commonupload組件。
?
謝謝兄弟指點,我會按照您的指點嘗試一下。
2015年3月21日 15:25?|?#?|?引用
請問發(fā)送數(shù)據(jù)時,可否發(fā)送blob數(shù)據(jù)?文章只說了接收數(shù)據(jù)可以接收blob
2015年7月25日 17:37?|?#?|?引用
謝謝阮兄,剛好要用到這個知識點!
2015年11月 6日 11:19?|?#?|?引用
使用阮老師提供的formData對象上傳的文件(異步方式),后臺(java)不知道該如何解析啊,求各位大神指點,謝謝!
2016年1月14日 22:28?|?#?|?引用
謝謝樓主大大!感覺收獲良多!
2016年3月20日 19:02?|?#?|?引用
使用起來和Android的AsyncTask挺像啊
2016年3月28日 12:23?|?#?|?引用
引用山姆大叔的發(fā)言:
使用阮老師提供的formData對象上傳的文件(異步方式),后臺(java)不知道該如何解析啊,求各位大神指點,謝謝!
java沒有像php的$_FILES類嗎,一樣的處理方式啊,和直接form提交沒啥區(qū)別吧2016年5月 4日 17:14?|?#?|?引用
引用請問阮老師的發(fā)言:
請問發(fā)送數(shù)據(jù)時,可否發(fā)送blob數(shù)據(jù)?文章只說了接收數(shù)據(jù)可以接收blob
void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);
2016年5月 4日 17:17?|?#?|?引用
問下,關(guān)于上傳進(jìn)度 【event.loaded是已經(jīng)傳輸?shù)淖止?jié)】 event里面的數(shù)據(jù)是從本地獲取的還是服務(wù)的返回的?
2016年6月12日 15:28?|?#?|?引用
onreadystatechange應(yīng)該在open和send之前設(shè)定吧,否則一些狀態(tài)會捕捉不到
2016年7月29日 00:30?|?#?|?引用
引用阮老師你好的發(fā)言:
onreadystatechange應(yīng)該在open和send之前設(shè)定吧,否則一些狀態(tài)會捕捉不到
現(xiàn)在使用onload
2017年3月17日 12:10?|?#?|?引用
文件進(jìn)度需要服務(wù)端支持把,能不能寫幾行服務(wù)端的偽代碼,我們也好理解
2018年3月28日 12:50?|?#?|?引用
引用小小蘇的發(fā)言:
文件進(jìn)度需要服務(wù)端支持把,能不能寫幾行服務(wù)端的偽代碼,我們也好理解
這個應(yīng)該不需要服務(wù)端支持吧
2018年3月28日 15:30?|?#?|?引用
我要發(fā)表看法
轉(zhuǎn)載于:https://www.cnblogs.com/yaowen/p/8759423.html
總結(jié)
以上是生活随笔為你收集整理的XMLHttpRequest Level 2 使用指南的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于Ajax 4-9
- 下一篇: SELinux的开启和关闭