详解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 相关文章推荐
分享8款优秀的 jQuery 加载动画和进度条插件
Oct 24 Javascript
jquery的ajax异步请求接收返回json数据实例
Jun 16 Javascript
值得分享和收藏的Bootstrap学习教程
May 12 Javascript
js实现div模拟模态对话框展现URL内容
May 27 Javascript
BootStrap使用popover插件实现鼠标经过显示并保持显示框
Jun 23 Javascript
JS判断是否在微信浏览器打开的简单实例(推荐)
Aug 24 Javascript
详解用vue-cli来搭建vue项目和webpack
Apr 20 Javascript
详解Vue组件之间的数据通信实例
Jun 17 Javascript
jQuery pjax 应用简单示例
Sep 20 jQuery
uni-app微信小程序登录并使用vuex存储登录状态的思路详解
Nov 04 Javascript
vue实现户籍管理系统
May 29 Javascript
详解Vue中Axios封装API接口的思路及方法
Oct 10 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
phpMyAdmin下载、安装和使用入门教程
2007/05/31 PHP
探讨GDFONTPATH能否被winxp下的php支持
2013/06/21 PHP
ThinkPHP自定义函数解决模板标签加减运算的方法
2015/07/03 PHP
Yii2框架引用bootstrap中日期插件yii2-date-picker的方法
2016/01/09 PHP
PHP版单点登陆实现方案的实例
2016/11/17 PHP
PHP实现mysqli批量执行多条语句的方法示例
2017/07/22 PHP
php基于session锁防止阻塞请求的方法分析
2017/08/07 PHP
神奇的代码 通杀各种网站-可随意修改复制页面内容
2008/07/17 Javascript
jquery HotKeys轻松搞定键盘事件代码
2008/08/30 Javascript
javascript实现类似超链接的效果
2014/12/26 Javascript
JavaScript中函数声明与函数表达式的区别详解
2016/08/18 Javascript
jQuery autoComplete插件两种使用方式及动态改变参数值的方法详解
2016/10/24 Javascript
Vue.js tab实现选项卡切换
2017/05/16 Javascript
vue 使用自定义指令实现表单校验的方法
2018/08/28 Javascript
vue-cli 打包后提交到线上出现 &quot;Uncaught SyntaxError:Unexpected token&quot; 报错
2018/11/06 Javascript
centos6.4下python3.6.1安装教程
2017/07/21 Python
Python:Scrapy框架中Item Pipeline组件使用详解
2017/12/27 Python
python实现堆和索引堆的代码示例
2018/03/19 Python
Python操作配置文件ini的三种方法讲解
2019/02/22 Python
详解python opencv、scikit-image和PIL图像处理库比较
2019/12/26 Python
完美解决pyinstaller打包报错找不到依赖pypiwin32或pywin32-ctypes的错误
2020/04/01 Python
python中判断文件结束符的具体方法
2020/08/04 Python
详解python爬取弹幕与数据分析
2020/11/14 Python
matplotlib 使用 plt.savefig() 输出图片去除旁边的空白区域
2021/01/05 Python
使用css3绘制出各种几何图形
2016/08/17 HTML / CSS
HTML5 MiranaVideo播放器 (代码开源)
2010/06/11 HTML / CSS
html5+css如何实现中间大两头小的轮播效果
2018/12/06 HTML / CSS
意大利简约的休闲品牌:Aspesi
2018/02/08 全球购物
泰国最新活动和优惠:Megatix
2020/05/07 全球购物
商场经理竞聘演讲稿
2014/01/01 职场文书
《风筝》教学反思
2014/04/10 职场文书
学校三八妇女节活动总结
2015/02/06 职场文书
Nginx反爬虫策略,防止UA抓取网站
2021/03/31 Servers
Windows下redis下载、redis安装及使用教程
2021/06/02 Redis
在python中读取和写入CSV文件详情
2022/06/28 Python
Win11 Build 25179预览版发布(附更新内容+ISO官方镜像下载)
2022/08/14 数码科技