详解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 相关文章推荐
自己的js工具 Cookie 封装
Aug 21 Javascript
jQuery 1.8 Release版本发布了
Aug 14 Javascript
纯js简单日历实现代码
Oct 05 Javascript
jquery遍历筛选数组的几种方法和遍历解析json对象
Dec 13 Javascript
如何用JavaScript定义一个类
Sep 12 Javascript
使用node.js 制作网站前台后台
Nov 13 Javascript
基于jQuery实现网页打印功能
Dec 01 Javascript
javascript针对不确定函数的执行方法
Dec 16 Javascript
精彩的Bootstrap案例分享 重点在注释!(选项卡、栅格布局)
Jul 01 Javascript
Node.js学习之TCP/IP数据通讯(实例讲解)
Oct 11 Javascript
JavaScript面试技巧之数组的一些不low操作
Mar 22 Javascript
详解Howler.js Web音频播放终极解决方案
Aug 23 Javascript
详解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
用PHP书写安全的脚本代码
2012/02/05 PHP
php实现批量压缩图片文件大小的脚本
2014/07/04 PHP
PHP面试常用算法(推荐)
2016/07/22 PHP
Laravel如何自定义command命令浅析
2019/03/23 PHP
yii2.0框架多模型操作示例【添加/修改/删除】
2020/04/13 PHP
开发跨浏览器javascript常见注意事项
2009/01/01 Javascript
jQuery AJAX 调用WebService实现代码
2010/03/24 Javascript
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
js jq 单击和双击区分示例介绍
2013/11/05 Javascript
Node.js中使用计时器定时执行函数详解
2014/08/15 Javascript
laytpl 精致巧妙的JavaScript模板引擎
2014/08/29 Javascript
浅析javascript的间隔调用和延时调用
2014/11/12 Javascript
JavaScript中Function详解
2015/02/27 Javascript
jQuery插件zTree实现获取当前选中节点在同级节点中序号的方法
2017/03/08 Javascript
基于LayUI分页和LayUI laypage分页的使用示例
2017/08/02 Javascript
帝国cms首页列表页实现点赞功能
2017/10/30 Javascript
js中如何完美的解析数据
2018/03/18 Javascript
webpack HappyPack实战详解
2019/10/08 Javascript
JavaScript canvas实现跟随鼠标移动小球
2021/02/09 Javascript
python翻译软件实现代码(使用google api完成)
2013/11/26 Python
Python中集合类型(set)学习小结
2015/01/28 Python
Python正则表达式匹配HTML页面编码
2015/04/08 Python
基于wxpython实现的windows GUI程序实例
2015/05/30 Python
Python解析最简单的验证码
2016/01/07 Python
Python爬取附近餐馆信息代码示例
2017/12/09 Python
30秒轻松实现TensorFlow物体检测
2018/03/14 Python
tensorflow实现简单的卷积神经网络
2018/05/24 Python
利用pyecharts实现地图可视化的例子
2019/08/12 Python
手摸手教你用canvas实现给图片添加平铺水印的实现
2019/08/20 HTML / CSS
实习单位接收函模板
2014/01/10 职场文书
办公室务虚会发言材料
2014/10/20 职场文书
入党积极分子十八届四中全会思想汇报
2014/10/23 职场文书
2014年世界艾滋病日演讲稿
2014/11/28 职场文书
建国大业观后感
2015/06/01 职场文书
湘江北去观后感
2015/06/15 职场文书
python基础之停用词过滤详解
2021/04/21 Python