详解XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度


Posted in Javascript onSeptember 14, 2016

分析并操作 responseXML属性 

如果你使用 XMLHttpRequest 来获得一个远程的 XML 文档的内容,responseXML 属性将会是一个由 XML 文档解析而来的 DOM 对象,这很难被操作和分析。这里有五种主要的分析 XML 文档的方式:
 1.使用 XPath 定位到文档的制定部分。
 2.使用 JXON 将其转换成 JavaScript 对象树。
 3.手工的 解析和序列化 XML 为字符串或对象。
 4.使用 XMLSerializer 把 DOM 树序列化成字符串或文件。
 5.如果你预先知道 XML 文档的内容,你可以使用 RegExp。如果你用 RegExp 扫描时受到换行符的影响,你也许想要删除所有的换行符。然而,这种方法是"最后手段",因为如果 XML 代码发生轻微变化,该方法将可能失败。 

解析和操作包含 HTML 文档的 responseText 属性 

注意: 在 W3C XMLHttpRequest 规范中允许 HTML 通过 XMLHttpRequest.responseXML 属性进行解析。更多详细内容请阅读 HTML in XMLHttpRequest 。
 如果使用 XMLHttpRequest 从远端获取一个 HTML 页面,则所有 HTML 标记会以字符串的形式存放在responseText 属性里,这样就使得操作和解析这些标记变得困难。解析这些HTML标记主要有三种方式:
 1.使用 XMLHttpRequest.responseXML 属性。
 2.将内容通过 fragment.body.innerHTML 注入到一个 文档片段 中,并遍历 DOM 中的片段。
 3.如果你预先知道 HTML 文档的内容,你可以使用 RegExp 。如果你用 RegExp 扫描时受到换行符的影响,你也许想要删除所有的换行符。 然而,这种方法是"最后手段",因为如果 HTML 代码发生轻微变化,该方法将可能失败。 

Handling binary data 

尽管 XMLHttpRequest 一般用来发送和接收文本数据,但其实也可以发送和接受二进制内容。有许多经过良好测试的方法来强制使用 XMLHttpRequest 发送二进制数据。利用 XMLHttpRequest 的 .overrideMimeType() 方法是一个解决方案,虽然它并不是一个标准方法。

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 规范中新加入了 responseType 属性 ,使得发送和接收二进制数据变得更加容易。

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类型数组接受二进制数据 

可以通过设置一个XMLHttpRequest对象的responseType属性来改变一个从服务器上返回的响应的数据类型.可用的属性值为空字符串 (默认), "arraybuffer", "blob", "document", 和 "text". response属性的值会根据responseType属性的值的不同而不同, 可能会是一个 ArrayBuffer, Blob, Document, string,或者为NULL(如果请求未完成或失败)
 下例读取了一个二进制图像文件,并且由该文件的二进制原生字节创建了一个8位无符号整数的数组.

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++) {
   // 对数组中的每个字节进行操作
  }
 }
};
oReq.send(null);

除了上面的方法,还可以使用 BlobBuilder API 直接将arraybuffer数据添加进一个Blob对象中, 由于该API还在试验阶段,所以需要加上特定的前缀:

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();

在老的浏览器中接受二进制数据
 下面的load_binary_resource()方法可以从指定的URL那里加载二进制数据,并将数据返回给调用者.

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;
}

最为奇妙的操作在第五行,该行重写了默认的MIME类型,强制浏览器将该响应当成纯文本文件来对待, 使用一个用户自定义的字符集.这样就是告诉了浏览器,不要去解析数据,直接返回未处理过的字节码.

var filestream = load_binary_resource(url);
var abyte = filestream.charCodeAt(x) & 0xff; // 扔掉的高位字节(f7)

上例从请求回来的二进制数据中得到偏移量为x处的字节.有效的偏移量范围是0到filestream.length-1.
 查看 使用XMLHttpRequest下载文件 了解详情,查看下载文件.

 发送二进制数据

 XMLHttpRequest对象的send方法已被增强,可以通过简单的传入一个ArrayBuffer, Blob, 或者 File对象来发送二进制数据.
 下例创建了一个文本文件,并使用POST方法将该文件发送到了服务器上.你也可以使用文本文件之外的其他二进制数据类型.

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\'));

将类型数组作为二进制数据发送
 你可以将JavaScript类型数组作为二进制数据发送出去.

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);

上例新建了一个512字节的8位整数数组并发送它,当然,你也可以发送任意的二进制数据

 监测进度
 支持 DOM 的 progress 事件监测之于 XMLHttpRequest 传输,遵循 Web API 进度事件规范 : 这些事件实现了 ProgressEvent 接口。

var req = new XMLHttpRequest();
//上传监听
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
 }
}

注意: 你需要在请求调用 open() 之前添加事件监听。否则 progress 事件将不会被触发。
 在上个例子中,progress 事件被指定由 updateProgress() 函数处理,并接收到传输的总字节数 total 和已经传输的字节数loaded ,total是自“Content-Length”头传输的数据的整体长度(字节)。但是如果 lengthComputable 属性的值是 false,那么总字节数是未知并且 total 的值为0,若知道长度则lengthComputable属性为true
 progress 事件同时存在于下载和上传的传输。下载相关事件在 XMLHttpRequest 对象上被触发,就像上面的例子一样。上传相关事件在 XMLHttpRequest.upload 对象上被触发,像下面这样:

var req = new XMLHttpRequest();
//下载监听
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 (new XMLHttpRequest())){ //检测是否支持progress事件
  var request = new XMLHttpRequest();
  request.onprogress = function (e) {
    if(e.lengthComputable){
      progress.innerHTML = Math.round(100* e.loaded/ e.total) + \'%\';
    }
  }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
使用jquery实现放大镜效果
Sep 02 Javascript
js对象的复制继承实例
Jan 10 Javascript
如何防止JavaScript自动插入分号
Nov 05 Javascript
底部悬浮通栏可以关闭广告位的实现方法
Jun 01 Javascript
JS取数字小数点后两位或n位的简单方法
Oct 24 Javascript
原生js实现旋转木马轮播图效果
Feb 27 Javascript
Ionic2开发环境搭建教程
Aug 20 Javascript
zTree 树插件实现全国五级地区点击后加载的示例
Feb 05 Javascript
webpack 4.0.0-beta.0版本新特性介绍
Feb 10 Javascript
vue生成token并保存到本地存储中
Jul 17 Javascript
JS+HTML5 canvas绘制验证码示例
Dec 05 Javascript
JQuery获取元素尺寸、位置及页面滚动事件应用示例
May 14 jQuery
详解XMLHttpRequest(一)同步请求和异步请求
Sep 14 #Javascript
AngularJs ng-route路由详解及实例代码
Sep 14 #Javascript
js实现文字截断功能
Sep 14 #Javascript
jQuery版AJAX简易封装代码
Sep 14 #Javascript
原生JS实现首页进度加载动画
Sep 14 #Javascript
jquery判断iPhone、Android设备类型
Sep 14 #Javascript
Angularjs 实现分页功能及示例代码
Sep 14 #Javascript
You might like
apache+mysql+php+ssl服务器之完全安装攻略
2006/09/05 PHP
PHP怎样调用MSSQL的存储过程
2006/10/09 PHP
解析php开发中的中文编码问题
2013/08/08 PHP
PHP设计模式之工厂方法设计模式实例分析
2018/04/25 PHP
PHP与Perl之间知识点区别整理
2019/03/19 PHP
使用laravel指定日志文件记录任意日志
2019/10/17 PHP
在JavaScript中实现命名空间
2006/11/23 Javascript
50个比较实用jQuery代码段
2011/09/18 Javascript
js滚动条回到顶部的代码
2011/12/06 Javascript
js通过更改按钮的显示样式实现按钮的滑动效果
2014/04/23 Javascript
node.js中的path.basename方法使用说明
2014/12/09 Javascript
jQuery中contents()方法用法实例
2015/01/08 Javascript
自定义函数实现IE7与IE8不兼容js中trim函数的问题
2015/02/03 Javascript
简介JavaScript中的setTime()方法的使用
2015/06/11 Javascript
详解html-webpack-plugin用法全解
2018/01/22 Javascript
详解redis在nodejs中的应用
2018/05/02 NodeJs
JS实现点击li标签弹出对应的索引功能【案例】
2019/02/18 Javascript
一百行JS代码实现一个校验工具
2019/04/30 Javascript
微信小程序 swiper 组件遇到的问题及解决方法
2019/05/26 Javascript
基于vue和websocket的多人在线聊天室
2020/02/01 Javascript
JavaScript实现手风琴效果
2021/02/18 Javascript
Python中dictionary items()系列函数的用法实例
2014/08/21 Python
Django实现图片文字同时提交的方法
2015/05/26 Python
Python实现统计单词出现的个数
2015/05/28 Python
对python .txt文件读取及数据处理方法总结
2018/04/23 Python
python GUI库图形界面开发之PyQt5时间控件QTimer详细使用方法与实例
2020/02/26 Python
Python类的绑定方法和非绑定方法实例解析
2020/03/04 Python
简单了解python调用其他脚本方法实例
2020/03/26 Python
TensorFlow Autodiff自动微分详解
2020/07/06 Python
加拿大在线旅游公司:Flighthub
2019/03/11 全球购物
Abbott Lyon官网:女士手表、珠宝及配件
2020/12/26 全球购物
学前教育教师求职自荐信
2013/09/22 职场文书
2014年民政局关于保密工作整改措施
2014/09/19 职场文书
2014年机关作风建设工作总结
2014/10/23 职场文书
巾帼文明岗事迹材料
2014/12/24 职场文书
2015庆祝七一建党节94周年活动总结
2015/03/20 职场文书