详细解读XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度
本文主要参考:MDN
分析并操作 responseXML属性
如果你使用 XMLHttpRequest 来获得一个远程的 XML 文档的内容,responseXML 属性将会是一个由 XML 文档解析而来的 DOM 对象,这很难被操作和分析。这里有五种主要的分析 XML 文档的方式:
- 使用 XPath 定位到文档的制定部分。
- 使用 JXON 将其转换成 JavaScript 对象树。
- 手工的 解析和序列化 XML 为字符串或对象。
- 使用 XMLSerializer 把 DOM 树序列化成字符串或文件。
- 如果你预先知道 XML 文档的内容,你可以使用 RegExp。如果你用 RegExp 扫描时受到换行符的影响,你也许想要删除所有的换行符。然而,这种方法是"最后手段",因为如果 XML 代码发生轻微变化,该方法将可能失败。
解析和操作包含 HTML 文档的 responseText 属性
注意: 在 W3C XMLHttpRequest 规范中允许 HTML 通过 XMLHttpRequest.responseXML 属性进行解析。更多详细内容请阅读 HTML in XMLHttpRequest 。
如果使用 XMLHttpRequest 从远端获取一个 HTML 页面,则所有 HTML 标记会以字符串的形式存放在responseText 属性里,这样就使得操作和解析这些标记变得困难。解析这些HTML标记主要有三种方式:
- 使用 XMLHttpRequest.responseXML 属性。
- 将内容通过 fragment.body.innerHTML 注入到一个 文档片段 中,并遍历 DOM 中的片段。
- 如果你预先知道 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) + \'%\';
}
}
}
详细解读XMLHttpRequest(二)响应属性、二进制数据、监测上传下载进度的更多相关文章
- 使用Typescript重构axios(二十五)——文件上传下载进度监控
0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...
- SpringMVC——返回JSON数据&&文件上传下载
--------------------------------------------返回JSON数据------------------------------------------------ ...
- EasyNVR摄像机网页Chrome无插件视频播放功能二次开发之通道配置文件上传下载示例代码
背景需求 熟悉EasyNVR产品的朋友们都知道,产品设计初期根据整个直播流程层级,我们将EasyNVR无插件直播系统划分为:硬件层.能力层.应用层,连接硬件与应用之间的桥梁,同时屏蔽各种厂家硬件的不同 ...
- maven入门 (二)_私服安装与上传下载
本篇文章主要介绍maven的私服安装和 jar包的上传与下载.毕竟大家还是在公司需要上传jar包到自己公司私服的. 1.安装私服 下载链接: https://pan.baidu.com/s/17dbQ ...
- iOS开发AFN使用二:AFN文件下载与文件上传
#import "ViewController.h" #import "AFNetworking.h" @interface ViewController () ...
- php canvas 前端JS压缩,获取图片二进制流数据并上传
<?php if(isset($_GET['upload']) && $_GET['upload'] == 'img'){ //二进制数据流 $data = file_get_c ...
- Java Web(十二) commons-fileupload上传下载
今天心态正常...继续努力.. --WH 一.上传原理和代码分析. 上传:我们把需要上传的资源,发送给服务器,在服务器上保存下来. 下载:下载某一个资源时,将服务器上的该资源发送给浏览器. 难点:服务 ...
- Solr.NET快速入门(九)【二进制文档上传】【完】
二进制文档上传 SolrNet支持Solr"提取"功能(a.k.a. Solr"Cell")从二进制文档格式(如Word,PDF等)索引数据. 这里有一个简单的 ...
- JAVA Web 之 struts2文件上传下载演示(二)(转)
JAVA Web 之 struts2文件上传下载演示(二) 一.文件上传演示 详细查看本人的另一篇博客 http://titanseason.iteye.com/blog/1489397 二.文件下载 ...
随机推荐
- Android TextView高级特性使用
TextView一般都是用来显示一段文本,这里说的高级特性主要是一些我们平常不太常用的属性.包括文字阴影.自定义字体.html嵌入多格式.字体加粗.插入图片.这些特性平时开发APP的时候,可能一般使用 ...
- CSS3的学习--实现瀑布流
基于CSS3实现瀑布流,使用CSS3的CSS 多栏(Multi-column). 可以到github上下载源码 : https://github.com/CraryPrimitiveMan/water ...
- [c++] Iterators
性质depends on various containers. 需要躲过的坑,野指针. int main() { cout << "Hello World!" < ...
- unity3d中 刚体(Rigidbody) 碰撞体(Collider) 触发器(Is Trigger)
刚体(Rigidbody)的官方(摘自Unity3d的官方指导书<Unity4.x从入门到精通>)解释如下: Rigidbody(刚体)组件可使游戏对象在物理系统的控制下来运动,刚体可 ...
- Java魔法堂:JVM的运行模式
一.前言 JVM有Client和Server两种运行模式.不同的模式对应不同的应用场景,而JVM也会有相应的优化.本文将记录JVM模式的信息,以便日后查阅. 二.介绍 在$JAVA_HOME/jre/ ...
- 提取KIndle中每本书的笔记并单独保存
整体思路 目标:将Kindle中的每本书的笔记标注单独提取出保存为一个Markdown文件 其中检测KIndle是否已经正常插入的判断方法: 思路1:读取媒介挂载记录 思路2:直接判断挂载地址是否存在 ...
- 一个有意思的js小问题
问题:如何实现以下函数? add(2, 5); // 7 add(2)(5); // 7 第一个就不用说了,很简单,关键是看第二个,add(2)(5),可见add(2)应该返回的是一个函数,这个函数再 ...
- C# 模拟提交 Form表单的数据
用 HttpWebRequest Post方法模拟提交Form表单数据时,需要设置 ContentType 为 "application/x-www-form-urlencoded" ...
- ASP.NET MVC使用jQuery实现Autocomplete
Insus.NET的以前的ASP.NET MVC的练习中,也有实现过Autocomplete的功能.依次是使用jQuery来实现. 首先在数据库准备一些数据: CREATE TABLE [dbo].[ ...
- c#隐藏和重写基类方法的异同
最近正在学习c#,对其中的方法重写和隐藏的概念很是模糊,现在将其归纳如下: 1:方法重写:就是在基类中的方法用virtual关键字来标识,然后在继承类中对该类进行重写(override),这样基类中的 ...