详解XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度
分析并操作responseXML属性
如果你使用XMLHttpRequest来获得一个远程的XML文档的内容,responseXML属性将会是一个由XML文档解析而来的DOM对象,这很难被操作和分析。这里有五种主要的分析XML文档的方式:
1.使用XPath定位到文档的制定部分。
2.使用JXON将其转换成JavaScript对象树。
3.手工的解析和序列化XML为字符串或对象。
4.使用XMLSerializer把DOM树序列化成字符串或文件。
5.如果你预先知道XML文档的内容,你可以使用RegExp。如果你用RegExp扫描时受到换行符的影响,你也许想要删除所有的换行符。然而,这种方法是"最后手段",因为如果XML代码发生轻微变化,该方法将可能失败。
解析和操作包含HTML文档的responseText属性
注意:在W3CXMLHttpRequest规范中允许HTML通过XMLHttpRequest.responseXML属性进行解析。更多详细内容请阅读HTMLinXMLHttpRequest。
如果使用XMLHttpRequest从远端获取一个HTML页面,则所有HTML标记会以字符串的形式存放在responseText属性里,这样就使得操作和解析这些标记变得困难。解析这些HTML标记主要有三种方式:
1.使用XMLHttpRequest.responseXML属性。
2.将内容通过fragment.body.innerHTML注入到一个文档片段中,并遍历DOM中的片段。
3.如果你预先知道HTML文档的内容,你可以使用RegExp。如果你用RegExp扫描时受到换行符的影响,你也许想要删除所有的换行符。然而,这种方法是"最后手段",因为如果HTML代码发生轻微变化,该方法将可能失败。
Handlingbinarydata
尽管XMLHttpRequest一般用来发送和接收文本数据,但其实也可以发送和接受二进制内容。有许多经过良好测试的方法来强制使用XMLHttpRequest发送二进制数据。利用XMLHttpRequest的.overrideMimeType()方法是一个解决方案,虽然它并不是一个标准方法。
varoReq=newXMLHttpRequest();
oReq.open("GET",url,true);
//retrievedataunprocessedasabinarystring
oReq.overrideMimeType("text/plain;charset=x-user-defined");
/*...*/
在XMLHttpRequestLevel2规范中新加入了responseType属性,使得发送和接收二进制数据变得更加容易。
varoReq=newXMLHttpRequest();
oReq.onload=function(e){
vararraybuffer=xhr.response;//notresponseText
/*...*/
}
oReq.open("GET",url,true);
oReq.responseType="arraybuffer";
oReq.send();
使用JavaScript类型数组接受二进制数据
可以通过设置一个XMLHttpRequest对象的responseType属性来改变一个从服务器上返回的响应的数据类型.可用的属性值为空字符串(默认),"arraybuffer","blob","document",和"text".response属性的值会根据responseType属性的值的不同而不同,可能会是一个ArrayBuffer,Blob,Document,string,或者为NULL(如果请求未完成或失败)
下例读取了一个二进制图像文件,并且由该文件的二进制原生字节创建了一个8位无符号整数的数组.
varoReq=newXMLHttpRequest();
oReq.open("GET","/myfile.png",true);
oReq.responseType="arraybuffer";
oReq.onload=function(oEvent){
vararrayBuffer=oReq.response;//注意:不是oReq.responseText
if(arrayBuffer){
varbyteArray=newUint8Array(arrayBuffer);
for(vari=0;i<byteArray.byteLength;i++){
//对数组中的每个字节进行操作
}
}
};
oReq.send(null);
除了上面的方法,还可以使用BlobBuilderAPI直接将arraybuffer数据添加进一个Blob对象中,由于该API还在试验阶段,所以需要加上特定的前缀:
varBlobBuilder=window.MozBlobBuilder||window.WebKitBlobBuilder||window.MSBlobBuilder||window.BlobBuilder;
varoReq=newXMLHttpRequest();
oReq.open("GET","/myfile.png",true);
oReq.responseType="arraybuffer";
oReq.onload=function(oEvent){
varblobBuilder=newBlobBuilder();
blobBuilder.append(oReq.response);
varblob=blobBuilder.getBlob("image/png");
//...
};
oReq.send();
在老的浏览器中接受二进制数据
下面的load_binary_resource()方法可以从指定的URL那里加载二进制数据,并将数据返回给调用者.
functionload_binary_resource(url){
varreq=newXMLHttpRequest();
req.open(\'GET\',url,false);
//XHRbinarycharsetoptbyMarcusGranado2006[http://mgran.blogspot.com]
req.overrideMimeType(\'text/plain;charset=x-user-defined\');
req.send(null);
if(req.status!=200)return\'\';
returnreq.responseText;
}
最为奇妙的操作在第五行,该行重写了默认的MIME类型,强制浏览器将该响应当成纯文本文件来对待,使用一个用户自定义的字符集.这样就是告诉了浏览器,不要去解析数据,直接返回未处理过的字节码.
varfilestream=load_binary_resource(url); varabyte=filestream.charCodeAt(x)&0xff;//扔掉的高位字节(f7)
上例从请求回来的二进制数据中得到偏移量为x处的字节.有效的偏移量范围是0到filestream.length-1.
查看使用XMLHttpRequest下载文件了解详情,查看下载文件.
发送二进制数据
XMLHttpRequest对象的send方法已被增强,可以通过简单的传入一个ArrayBuffer,Blob,或者File对象来发送二进制数据.
下例创建了一个文本文件,并使用POST方法将该文件发送到了服务器上.你也可以使用文本文件之外的其他二进制数据类型.
varoReq=newXMLHttpRequest();
oReq.open("POST",url,true);
oReq.onload=function(oEvent){
//上传完成后.
};
varbb=newBlobBuilder();//需要合适的前缀:window.MozBlobBuilder或者window.WebKitBlobBuilder
bb.append(\'abc123\');
oReq.send(bb.getBlob(\'text/plain\'));
将类型数组作为二进制数据发送
你可以将JavaScript类型数组作为二进制数据发送出去.
varmyArray=newArrayBuffer(512);
varlongInt8View=newUint8Array(myArray);
for(vari=0;i<longInt8View.length;i++){
longInt8View[i]=i%255;
}
varxhr=newXMLHttpRequest;
xhr.open("POST",url,false);
xhr.send(myArray);
上例新建了一个512字节的8位整数数组并发送它,当然,你也可以发送任意的二进制数据
监测进度
支持DOM的progress事件监测之于XMLHttpRequest传输,遵循WebAPI进度事件规范:这些事件实现了ProgressEvent接口。
varreq=newXMLHttpRequest();
//上传监听
req.addEventListener("progress",updateProgress,false);
req.addEventListener("load",transferComplete,false);
req.addEventListener("error",transferFailed,false);
req.addEventListener("abort",transferCanceled,false);
req.open(...);
...
//progressontransfersfromtheservertotheclient(downloads)
functionupdateProgress(evt){
if(evt.lengthComputable){
varpercentComplete=evt.loaded/evt.total;
...
}else{
//Unabletocomputeprogressinformationsincethetotalsizeisunknown
}
}
注意:你需要在请求调用open()之前添加事件监听。否则progress事件将不会被触发。
在上个例子中,progress事件被指定由updateProgress()函数处理,并接收到传输的总字节数total和已经传输的字节数loaded,total是自“Content-Length”头传输的数据的整体长度(字节)。但是如果lengthComputable属性的值是false,那么总字节数是未知并且total的值为0,若知道长度则lengthComputable属性为true
progress事件同时存在于下载和上传的传输。下载相关事件在XMLHttpRequest对象上被触发,就像上面的例子一样。上传相关事件在XMLHttpRequest.upload对象上被触发,像下面这样:
varreq=newXMLHttpRequest();
//下载监听
req.upload.addEventListener("progress",updateProgress);
req.upload.addEventListener("load",transferComplete);
req.upload.addEventListener("error",transferFailed);
req.upload.addEventListener("abort",transferCanceled);
req.open();
注意:progress事件在使用file:协议的情况下是无效的。
使用loadend事件可以侦测到所有的三种加载结束条件(abort、load、error):
req.addEventListener("loadend",loadEnd,false);
需要注意的是,没有方法可以确切的知道loadend事件接收到的信息是来自何种条件引起的操作终止;但是你可以在所有传输结束的时候使用这个事件处理。
XMLHttpRequest对象在请求的不同阶段触发不同类型的事件,所以它不需要检查readyState属性。
当调用send()时,触发单个loadstart事件。当正在加载服务器的响应时,XMLHttpRequest对象会发生progress事件,通常每隔50毫秒左右,所以可以使用这些事件给用户反馈请求的进度。
如果请求快速完成,它可能从不会触发progress事件。当事件完成,会触发load事件。
HTTP请求无法完成有3种情况,对应3种事件。如果请求超时,会触发timeout事件。如果请求中止,会触发abort事件。像太多重定向这样的网络错误会阻止请求完成,但这些情况发生时会触发error事件。
对于任何具体请求,浏览器将只会触发load、abort、timeout和error事件中的一个,还有progress事件。
if(\'onprogress\'in(newXMLHttpRequest())){//检测是否支持progress事件
varrequest=newXMLHttpRequest();
request.onprogress=function(e){
if(e.lengthComputable){
progress.innerHTML=Math.round(100*e.loaded/e.total)+\'%\';
}
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。