詳解XMLHttpRequest(二)響應(yīng)屬性、二進(jìn)制數(shù)據(jù)、監(jiān)測(cè)上傳下載進(jìn)度
分析并操作 responseXML屬性
如果你使用 XMLHttpRequest 來(lái)獲得一個(gè)遠(yuǎn)程的 XML 文檔的內(nèi)容,responseXML 屬性將會(huì)是一個(gè)由 XML 文檔解析而來(lái)的 DOM 對(duì)象,這很難被操作和分析。這里有五種主要的分析 XML 文檔的方式:
1.使用 XPath 定位到文檔的制定部分。
2.使用 JXON 將其轉(zhuǎn)換成 JavaScript 對(duì)象樹。
3.手工的 解析和序列化 XML 為字符串或?qū)ο蟆?br />
4.使用 XMLSerializer 把 DOM 樹序列化成字符串或文件。
5.如果你預(yù)先知道 XML 文檔的內(nèi)容,你可以使用 RegExp。如果你用 RegExp 掃描時(shí)受到換行符的影響,你也許想要?jiǎng)h除所有的換行符。然而,這種方法是"最后手段",因?yàn)槿绻?XML 代碼發(fā)生輕微變化,該方法將可能失敗。
解析和操作包含 HTML 文檔的 responseText 屬性
注意: 在 W3C XMLHttpRequest 規(guī)范中允許 HTML 通過(guò) XMLHttpRequest.responseXML 屬性進(jìn)行解析。更多詳細(xì)內(nèi)容請(qǐng)閱讀 HTML in XMLHttpRequest 。
如果使用 XMLHttpRequest 從遠(yuǎn)端獲取一個(gè) HTML 頁(yè)面,則所有 HTML 標(biāo)記會(huì)以字符串的形式存放在responseText 屬性里,這樣就使得操作和解析這些標(biāo)記變得困難。解析這些HTML標(biāo)記主要有三種方式:
1.使用 XMLHttpRequest.responseXML 屬性。
2.將內(nèi)容通過(guò) fragment.body.innerHTML 注入到一個(gè) 文檔片段 中,并遍歷 DOM 中的片段。
3.如果你預(yù)先知道 HTML 文檔的內(nèi)容,你可以使用 RegExp 。如果你用 RegExp 掃描時(shí)受到換行符的影響,你也許想要?jiǎng)h除所有的換行符。 然而,這種方法是"最后手段",因?yàn)槿绻?HTML 代碼發(fā)生輕微變化,該方法將可能失敗。
Handling binary data
盡管 XMLHttpRequest 一般用來(lái)發(fā)送和接收文本數(shù)據(jù),但其實(shí)也可以發(fā)送和接受二進(jìn)制內(nèi)容。有許多經(jīng)過(guò)良好測(cè)試的方法來(lái)強(qiáng)制使用 XMLHttpRequest 發(fā)送二進(jìn)制數(shù)據(jù)。利用 XMLHttpRequest 的 .overrideMimeType() 方法是一個(gè)解決方案,雖然它并不是一個(gè)標(biāo)準(zhǔn)方法。
var oReq = new XMLHttpRequest(); oReq.open("GET", url, true); // retrieve data unprocessed as a binary string oReq.overrideMimeType("text/plain; charset=x-user-defined"); /* ... */
在 XMLHttpRequest Level 2 規(guī)范中新加入了 responseType 屬性 ,使得發(fā)送和接收二進(jìn)制數(shù)據(jù)變得更加容易。
var oReq = new XMLHttpRequest(); oReq.onload = function(e) { var arraybuffer = xhr.response; // not responseText /* ... */ } oReq.open("GET", url, true); oReq.responseType = "arraybuffer"; oReq.send();
使用JavaScript類型數(shù)組接受二進(jìn)制數(shù)據(jù)
可以通過(guò)設(shè)置一個(gè)XMLHttpRequest對(duì)象的responseType屬性來(lái)改變一個(gè)從服務(wù)器上返回的響應(yīng)的數(shù)據(jù)類型.可用的屬性值為空字符串 (默認(rèn)), "arraybuffer", "blob", "document", 和 "text". response屬性的值會(huì)根據(jù)responseType屬性的值的不同而不同, 可能會(huì)是一個(gè) ArrayBuffer, Blob, Document, string,或者為NULL(如果請(qǐng)求未完成或失敗)
下例讀取了一個(gè)二進(jìn)制圖像文件,并且由該文件的二進(jìn)制原生字節(jié)創(chuàng)建了一個(gè)8位無(wú)符號(hào)整數(shù)的數(shù)組.
var oReq = new XMLHttpRequest(); oReq.open("GET", "/myfile.png", true); oReq.responseType = "arraybuffer"; oReq.onload = function (oEvent) { var arrayBuffer = oReq.response; // 注意:不是oReq.responseText if (arrayBuffer) { var byteArray = new Uint8Array(arrayBuffer); for (var i = 0; i < byteArray.byteLength; i++) { // 對(duì)數(shù)組中的每個(gè)字節(jié)進(jìn)行操作 } } }; oReq.send(null);
除了上面的方法,還可以使用 BlobBuilder API 直接將arraybuffer數(shù)據(jù)添加進(jìn)一個(gè)Blob對(duì)象中, 由于該API還在試驗(yàn)階段,所以需要加上特定的前綴:
var BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder || window.BlobBuilder; var oReq = new XMLHttpRequest(); oReq.open("GET", "/myfile.png", true); oReq.responseType = "arraybuffer"; oReq.onload = function(oEvent) { var blobBuilder = new BlobBuilder(); blobBuilder.append(oReq.response); var blob = blobBuilder.getBlob("image/png"); // ... }; oReq.send();
在老的瀏覽器中接受二進(jìn)制數(shù)據(jù)
下面的load_binary_resource()方法可以從指定的URL那里加載二進(jìn)制數(shù)據(jù),并將數(shù)據(jù)返回給調(diào)用者.
function load_binary_resource(url) { var req = new XMLHttpRequest(); req.open(\'GET\', url, false); //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com] req.overrideMimeType(\'text/plain; charset=x-user-defined\'); req.send(null); if (req.status != 200) return \'\'; return req.responseText; }
最為奇妙的操作在第五行,該行重寫了默認(rèn)的MIME類型,強(qiáng)制瀏覽器將該響應(yīng)當(dāng)成純文本文件來(lái)對(duì)待, 使用一個(gè)用戶自定義的字符集.這樣就是告訴了瀏覽器,不要去解析數(shù)據(jù),直接返回未處理過(guò)的字節(jié)碼.
var filestream = load_binary_resource(url); var abyte = filestream.charCodeAt(x) & 0xff; // 扔掉的高位字節(jié)(f7)
上例從請(qǐng)求回來(lái)的二進(jìn)制數(shù)據(jù)中得到偏移量為x處的字節(jié).有效的偏移量范圍是0到filestream.length-1.
查看 使用XMLHttpRequest下載文件 了解詳情,查看下載文件.
發(fā)送二進(jìn)制數(shù)據(jù)
XMLHttpRequest對(duì)象的send方法已被增強(qiáng),可以通過(guò)簡(jiǎn)單的傳入一個(gè)ArrayBuffer, Blob, 或者 File對(duì)象來(lái)發(fā)送二進(jìn)制數(shù)據(jù).
下例創(chuàng)建了一個(gè)文本文件,并使用POST方法將該文件發(fā)送到了服務(wù)器上.你也可以使用文本文件之外的其他二進(jìn)制數(shù)據(jù)類型.
var oReq = new XMLHttpRequest(); oReq.open("POST", url, true); oReq.onload = function (oEvent) { // 上傳完成后. }; var bb = new BlobBuilder(); // 需要合適的前綴: window.MozBlobBuilder 或者 window.WebKitBlobBuilder bb.append(\'abc123\'); oReq.send(bb.getBlob(\'text/plain\'));
將類型數(shù)組作為二進(jìn)制數(shù)據(jù)發(fā)送
你可以將JavaScript類型數(shù)組作為二進(jìn)制數(shù)據(jù)發(fā)送出去.
var myArray = new ArrayBuffer(512); var longInt8View = new Uint8Array(myArray); for (var i=0; i< longInt8View.length; i++) { longInt8View[i] = i % 255; } var xhr = new XMLHttpRequest; xhr.open("POST", url, false); xhr.send(myArray);
上例新建了一個(gè)512字節(jié)的8位整數(shù)數(shù)組并發(fā)送它,當(dāng)然,你也可以發(fā)送任意的二進(jìn)制數(shù)據(jù)
監(jiān)測(cè)進(jìn)度
支持 DOM 的 progress 事件監(jiān)測(cè)之于 XMLHttpRequest 傳輸,遵循 Web API 進(jìn)度事件規(guī)范 : 這些事件實(shí)現(xiàn)了 ProgressEvent 接口。
var req = new XMLHttpRequest(); //上傳監(jiān)聽 req.addEventListener("progress", updateProgress, false); req.addEventListener("load", transferComplete, false); req.addEventListener("error", transferFailed, false); req.addEventListener("abort", transferCanceled, false); req.open(...); ... // progress on transfers from the server to the client (downloads) function updateProgress(evt) { if (evt.lengthComputable) { var percentComplete = evt.loaded / evt.total; ... } else { // Unable to compute progress information since the total size is unknown } }
注意: 你需要在請(qǐng)求調(diào)用 open() 之前添加事件監(jiān)聽。否則 progress 事件將不會(huì)被觸發(fā)。
在上個(gè)例子中,progress 事件被指定由 updateProgress() 函數(shù)處理,并接收到傳輸?shù)目傋止?jié)數(shù) total 和已經(jīng)傳輸?shù)淖止?jié)數(shù)loaded ,total是自“Content-Length”頭傳輸?shù)臄?shù)據(jù)的整體長(zhǎng)度(字節(jié))。但是如果 lengthComputable 屬性的值是 false,那么總字節(jié)數(shù)是未知并且 total 的值為0,若知道長(zhǎng)度則lengthComputable屬性為true
progress 事件同時(shí)存在于下載和上傳的傳輸。下載相關(guān)事件在 XMLHttpRequest 對(duì)象上被觸發(fā),就像上面的例子一樣。上傳相關(guān)事件在 XMLHttpRequest.upload 對(duì)象上被觸發(fā),像下面這樣:
var req = new XMLHttpRequest(); //下載監(jiān)聽 req.upload.addEventListener("progress", updateProgress); req.upload.addEventListener("load", transferComplete); req.upload.addEventListener("error", transferFailed); req.upload.addEventListener("abort", transferCanceled); req.open();
注意:progress 事件在使用 file: 協(xié)議的情況下是無(wú)效的。
使用 loadend 事件可以偵測(cè)到所有的三種加載結(jié)束條件(abort、load、error):
req.addEventListener("loadend", loadEnd, false);
需要注意的是,沒有方法可以確切的知道 loadend 事件接收到的信息是來(lái)自何種條件引起的操作終止;但是你可以在所有傳輸結(jié)束的時(shí)候使用這個(gè)事件處理。
XMLHttpRequest對(duì)象在請(qǐng)求的不同階段觸發(fā)不同類型的事件,所以它不需要檢查readyState屬性。
當(dāng)調(diào)用send()時(shí),觸發(fā)單個(gè)loadstart事件。當(dāng)正在加載服務(wù)器的響應(yīng)時(shí),XMLHttpRequest對(duì)象會(huì)發(fā)生progress事件,通常每隔50毫秒左右,所以可以使用這些事件給用戶反饋請(qǐng)求的進(jìn)度。
如果請(qǐng)求快速完成,它可能從不會(huì)觸發(fā)progress事件。當(dāng)事件完成,會(huì)觸發(fā)load事件。
HTTP請(qǐng)求無(wú)法完成有3種情況,對(duì)應(yīng)3種事件。如果請(qǐng)求超時(shí),會(huì)觸發(fā)timeout事件。如果請(qǐng)求中止,會(huì)觸發(fā)abort事件。像太多重定向這樣的網(wǎng)絡(luò)錯(cuò)誤會(huì)阻止請(qǐng)求完成,但這些情況發(fā)生時(shí)會(huì)觸發(fā)error事件。
對(duì)于任何具體請(qǐng)求,瀏覽器將只會(huì)觸發(fā)load、abort、timeout和error事件中的一個(gè),還有progress事件。
if(\'onprogress\' in (new XMLHttpRequest())){ //檢測(cè)是否支持progress事件 var request = new XMLHttpRequest(); request.onprogress = function (e) { if(e.lengthComputable){ progress.innerHTML = Math.round(100* e.loaded/ e.total) + \'%\'; } } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- javascript XMLHttpRequest對(duì)象全面剖析
- AJAX(XMLHttpRequest.status)狀態(tài)碼
- XMLHTTPRequest的屬性和方法簡(jiǎn)介
- js判斷IE6/IE7/FF的代碼[XMLHttpRequest]
- Ajax xmlHttpRequest的status的值的含義
- AJAX中同時(shí)發(fā)送多個(gè)請(qǐng)求XMLHttpRequest對(duì)象處理方法
- jquery ajax學(xué)習(xí)筆記2 使用XMLHttpRequest對(duì)象的responseXML
- Javascript+XMLHttpRequest+asp.net無(wú)刷新讀取數(shù)據(jù)庫(kù)數(shù)據(jù)
- 一份老外寫的XMLHttpRequest代碼多瀏覽器支持兼容性
- 如何用ajax來(lái)創(chuàng)建一個(gè)XMLHttpRequest對(duì)象
相關(guān)文章
11個(gè)教程中不常被提及的JavaScript小技巧(推薦)
這篇文章主要介紹了11個(gè)教程中不常被提及的JavaScript小技巧,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04對(duì)Layer彈窗使用及返回?cái)?shù)據(jù)接收的實(shí)例詳解
今天小編就為大家分享一篇對(duì)Layer彈窗使用及返回?cái)?shù)據(jù)接收的實(shí)例詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-09-09詳解Webpack如何引入CDN鏈接來(lái)優(yōu)化編譯后的體積
這篇文章主要介紹了詳解Webpack如何引入CDN鏈接來(lái)優(yōu)化編譯后的體積,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06從盛大通行證上摘下來(lái)的身份證驗(yàn)證js代碼
偶然發(fā)現(xiàn)盛大通行證上的身份證驗(yàn)證代碼,特扒下來(lái),方便大家的使用。2011-01-01javascript設(shè)計(jì)模式之策略模式學(xué)習(xí)筆記
這篇文章主要介紹了javascript設(shè)計(jì)模式之策略模式學(xué)習(xí)筆記,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02underscore之function_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
因?yàn)閡nderscore本來(lái)就是為了充分發(fā)揮JavaScript的函數(shù)式編程特性,所以也提供了大量JavaScript本身沒有的高階函數(shù)。本文重點(diǎn)給大家介紹underscore之function知識(shí),感興趣的的朋友一起學(xué)習(xí)吧2017-07-07JavaScript高級(jí)程序設(shè)計(jì)(第三版)學(xué)習(xí)筆記6、7章
這篇文章主要介紹了JavaScript高級(jí)程序設(shè)計(jì)(第三版)學(xué)習(xí)筆記6、7章 的相關(guān)資料,需要的朋友可以參考下2016-03-03JavaScript實(shí)現(xiàn)微信小程序打卡時(shí)鐘項(xiàng)目實(shí)例
這篇文章主要為大家介紹了JavaScript實(shí)現(xiàn)微信小程序打卡時(shí)鐘項(xiàng)目實(shí)例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04