本文参考自:XMLHttpRequest2 新技巧 (重点保留demo,方便自己日后查阅)

HTML5是现在web开发中的热点,虽然关于web app和local app一直有争论,但是从技术学习的角度,html5技术无疑是值得学习的。最近看了看XHR2,大概了解了其中比之前进步的要点,记录下来以备日后复习:

首先,XHR2的官方注解可见:http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html

XHR2主要的新功能有(我平时开发遇到的):

  1. 上传下载二进制数据

  2. 上传进度事件的支持

  3. 跨域请求

同时结合html5中的File API,我们就可以在网页中实现更丰富的功能。

一) 二进制数据处理

以前通过 XHR 抓取二进制 blob 形式的文件是很痛苦的事情。从技术上来说,这甚至是不可能的实现。有一种广为流传的一种技巧,是将 MIME 类型替换为由用户定义的字符集,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var xhr = new XMLHttpRequest();
xhr.open('GET''/path/to/image.png'true);
  
xhr.overrideMimeType('text/plain; charset=x-user-defined');
  
xhr.onreadystatechange = function(e) {
  if (this.readyState == 4 && this.status == 200) {
    var binStr = this.responseText;
    for (var i = 0, len = binStr.length; i < len; ++i) {
      var c = binStr.charCodeAt(i);
      //String.fromCharCode(c & 0xff);
      var byte = c & 0xff;
    }
  }
};
  
xhr.send();

虽然这种方法可行,但是 responseText 中实际返回的并不是二进制 blob,而是代表图片文件的二进制字符串。我们要巧妙地让服务器在不作处理的情况下,将这些数据传递回去。

现在XHR2中,新增了responseType和response属性,可以告知浏览器我们希望返回什么格式的数据。

  1. xhr.responseType
    在发送请求前,根据您的数据需要,将 xhr.responseType 设置为“text”、“arraybuffer”、“blob”或“document”。请注意,设置(或忽略)xhr.responseType = '' 会默认将响应设为“text”。

  2. xhr.response

    成功发送请求后,xhr 的响应属性会包含 DOMString、ArrayBuffer、Blob 或 Document 形式(具体取决于 responseTyp  的设置)的请求数据。

凭借这个优秀的新属性,我们可以修改上一个示例:以 ArrayBuffer 而非字符串的形式抓取图片。将缓冲区移交给 BlobBuilder API 可创建 Blob:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
  
var xhr = new XMLHttpRequest();
xhr.open('GET''/path/to/image.png'true);
xhr.responseType = 'arraybuffer';
  
xhr.onload = function(e) {
  if (this.status == 200) {
    var bb = new BlobBuilder();
    bb.append(this.response); // Note: not xhr.responseText
  
    var blob = bb.getBlob('image/png');
    ...
  }
};
  
xhr.send();

此外ArrayBuffer是二进制数据通用的固定长度容器。如果您需要原始数据的通用缓冲区,ArrayBuffer 就非常好用,但是它真正强大的功能是让您使用 JavaScript 类型数组创建底层数据的“视图”。实际上,可以通过单个 ArrayBuffer 来源创建多个视图。例如,您可以创建一个 8 位整数数组,与来自相同数据的现有 32 位整数数组共享同一个 ArrayBuffer。底层数据保持不变,我们只是创建其不同的表示方法。

1
2
3
4
5
6
7
8
9
10
11
var xhr = new XMLHttpRequest();
xhr.open('GET''/path/to/image.png'true);
xhr.responseType = 'arraybuffer';
  
xhr.onload = function(e) {
  var uInt8Array = new Uint8Array(this.response); // this.response == uInt8Array.buffer
  // var byte3 = uInt8Array[4]; // byte at offset 4
  ...
};
  
xhr.send();

如果您要直接处理 Blob 且/或不需要操作任何文件的字节,可使用xhr.responseType='blob'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
window.URL = window.URL || window.webkitURL;  // Take care of vendor prefixes.
  
var xhr = new XMLHttpRequest();
xhr.open('GET''/path/to/image.png'true);
xhr.responseType = 'blob';
  
xhr.onload = function(e) {
  if (this.status == 200) {
    var blob = this.response;
  
    var img = document.createElement('img');
    img.onload = function(e) {
      window.URL.revokeObjectURL(img.src); // Clean up after yourself.
    };
    img.src = window.URL.createObjectURL(blob);
    document.body.appendChild(img);
    ...
  }
};
  
xhr.send();

Blob 可用于很多场合,包括保存到 indexedDB、写入 HTML5 文件系统 或创建 Blob 网址(如本例中所示)。

二)发送数据

能够下载各种格式的数据固然是件好事,但是如果不能将这些丰富格式的数据送回本垒(服务器),那就毫无意义了。XMLHttpRequest 有时候会限制我们发送 DOMString 或 Document (XML) 数据。但是现在不会了。现已替换成经过修改的 send() 方法,可接受以下任何类型:DOMString、Document、FormData、Blob、File、ArrayBuffer。本部分的其余内容中的示例演示了如何使用各类型发送数据。

1)发送字符串数据:xhr.send(DOMString)

1
2
3
4
5
6
7
8
9
10
11
12
13
function sendText(txt) {
  var xhr = new XMLHttpRequest();
  xhr.open('POST''/server'true);
  xhr.responseType ='text';  xhr.onload = function(e) {
    if (this.status == 200) {
      console.log(this.responseText);
    }
  };
  
  xhr.send(txt);
}
  
sendText('test string');

2)提交表单:xhr.send(FormData)

1
2
3
4
5
6
7
8
9
10
11
function sendForm() {
  var formData = new FormData();
  formData.append('username''johndoe');
  formData.append('id', 123456);
  
  var xhr = new XMLHttpRequest();
  xhr.open('POST''/server'true);
  xhr.onload = function(e) { ... };
  
  xhr.send(formData);
}

由form数据初始化formData

1
2
3
4
5
<form id="myform" name="myform" action="/server">
  <input type="text" name="username" value="johndoe">
  <input type="number" name="id" value="123456">
  <input type="submit" onclick="return sendForm(this.form);">
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
function sendForm(form) {
  var formData = new FormData(form);
  
  formData.append('secret_token''1234567890'); // Append extra data before send.
  
  var xhr = new XMLHttpRequest();
  xhr.open('POST', form.action, true);
  xhr.onload = function(e) { ... };
  
  xhr.send(formData);
  
  return false// Prevent page from submitting.
}

同时可以包含文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function uploadFiles(url, files) {
  var formData = new FormData();
  
  for (var i = 0, file; file = files[i]; ++i) {
    formData.append(file.name, file);
  }
  
  var xhr = new XMLHttpRequest();
  xhr.open('POST', url, true);
  xhr.onload = function(e) { ... };
  
  xhr.send(formData);  // multipart/form-data
}
  
document.querySelector('input[type="file"]').addEventListener('change',function(e) {
  uploadFiles('/server'this.files);
}, false);

3)上传文件或 blob:xhr.send(Blob),同时demo下上传事件如果使用

1
<progress min="0" max="100" value="0">0% complete</progress>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function upload(blobOrFile) {
  var xhr = new XMLHttpRequest();
  xhr.open('POST''/server'true);
  xhr.onload = function(e) { ... };
  
  // Listen to the upload progress.
  var progressBar = document.querySelector('progress');
  xhr.upload.onprogress = function(e) {
    if (e.lengthComputable) {
      progressBar.value = (e.loaded / e.total) * 100;
      progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
    }
  };
  
  xhr.send(blobOrFile);
}
  
// Take care of vendor prefixes.
BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.BlobBuilder;
  
var bb = new BlobBuilder();
bb.append('hello world');
  
upload(bb.getBlob('text/plain'));

4)上传字节:xhr.send(ArrayBuffer)

1
2
3
4
5
6
7
8
9
function sendArrayBuffer() {
  var xhr = new XMLHttpRequest();
  xhr.open('POST''/server'true);
  xhr.onload = function(e) { ... };
  
  var uInt8Array = new Uint8Array([1, 2, 3]);
  
  xhr.send(uInt8Array.buffer);
}

三)跨源请求 (CORS)

CORS 允许一个域上的网络应用向另一个域提交跨域 AJAX 请求。启用此功能非常简单,只需由服务器发送一个响应标头即可。

允许来自 example.com 的请求:

1
Access-Control-Allow-Origin: http://example.com

要允许任何域向您提交请求:

1
Access-Control-Allow-Origin: *

提交跨域请求时和以前没有区别。

1
2
3
4
5
6
7
var xhr = new XMLHttpRequest();
xhr.onload = function(e) {
  var data = JSON.parse(this.response);
  ...
}
xhr.send();

四)有用的实例

1)下载文件并保存到文件系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
window.requestFileSystem  = window.requestFileSystem || window.webkitRequestFileSystem;
  
function onError(e) {
  console.log('Error', e);
}
  
var xhr = new XMLHttpRequest();
xhr.open('GET''/path/to/image.png'true);
xhr.responseType = 'arraybuffer';
  
xhr.onload = function(e) {
  
  window.requestFileSystem(TEMPORARY, 1024 * 1024, function(fs) {
    fs.root.getFile('image.png', {create: true}, function(fileEntry) {
      fileEntry.createWriter(function(writer) {
  
        writer.onwrite = function(e) { ... };
        writer.onerror = function(e) { ... };
  
        var bb = new BlobBuilder();
        bb.append(xhr.response);
  
        writer.write(bb.getBlob('image/png'));
  
      }, onError);
    }, onError);
  }, onError);
};
  
xhr.send();

2)分割文件并上传各个部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
window.BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder ||
                     window.BlobBuilder;
  
function upload(blobOrFile) {
  var xhr = new XMLHttpRequest();
  xhr.open('POST''/server'true);
  xhr.onload = function(e) { ... };
  xhr.send(blobOrFile);
}
  
document.querySelector('input[type="file"]').addEventListener('change',function(e) {
  var blob = this.files[0];
  
  const BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes.
  const SIZE = blob.size;
  
  var start = 0;
  var end = BYTES_PER_CHUNK;
  
  while(start < SIZE) {
  
    // Note: blob.slice has changed semantics and been prefixed. Seehttp://goo.gl/U9mE5.
    if ('mozSlice' in blob) {
      var chunk = blob.mozSlice(start, end);
    else {
      var chunk = blob.webkitSlice(start, end);
    }
  
    upload(chunk);
  
    start = end;
    end = start + BYTES_PER_CHUNK;
  }
}, false);
  
})();

 

http://mozilla.com.cn/post/34886/

【JavsScript】XMLHttpRequest2的进步之处的更多相关文章

  1. XMLHttpRequest2的进步之处

    本文参考自:XMLHttpRequest2 新技巧 (重点保留demo,方便自己日后查阅) HTML5是现在web开发中的热点,虽然关于web app和local app一直有争论,但是从技术学习的角 ...

  2. Nginx CORS实现JS跨域

    1. 什么是跨域 简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象. 同源是指相同的协议.域名.端口.特别注意两点: 如果 ...

  3. JSONP、图片Ping、XMLHttpRequest2.0等跨域资源请求(CORS)

    跨域:当协议.主域名.子域名.端口号中任意一个不相同时都不算同一个域,而在不同域之间请求数据即为跨域请求.解决方法有以下几种(如有错误欢迎指出)以请求图片url为例: 1.通过XMLHttpReque ...

  4. CSS预处器的对比——Sass、Less和Stylus

    预处器的对比--Sass.LESS和Stylus 转载: 英文原文:http://net.tutsplus.com/tutorials/html-css-techniques/sass-vs-less ...

  5. 数据库(SQL Server)管理数据库表~新奇之处

    说到“数据库”,我总有一种莫名的感觉,在刚刚接触到的数据库中就让我似懂非懂渡过着,于是思考着.于是在冷静的时空中让我回想到了很多的知识,不知你们是怎样过来的,真心希望我的这篇数据库总结能够让我们都有一 ...

  6. Autocad 2012 win7(64位)启动时一直卡在acmgd.dll处的解决方案

    安装Autocad 2012后,激活成功后,无法正常启动,一直卡在加载acmgd.dll 通过Procmon监控后发现加载C:\Windows\fonts\AdobeFnt11.lst处出错, 通过命 ...

  7. this的安身之处

    在JavaScript的大千世界中,this对象就像一个行踪不定.居无定所的浪子一般,它的生活仿佛可以随处而安,而内心却又似有着笃定的坚守,它就是这么有趣! 初学JavaScript时的我们,多多少少 ...

  8. JavsScript+dom

    JavsScript+dom DOM(兼容性) 用于操作文档树 1.帮助我们找到标签 直接查找 间接查找 getElementById getElementsByTageName 2.标签操作 内容: ...

  9. OO方式下,ALV TREE和ALV GRID的不同之处

    作为大部分报表程序的基础,ALV GRID差不多是每个ABAP开发者必须了解和掌握的内容,因此网上也不乏相关资料,而ALV TREE的应用相对较少,中文资料也就比较少见了.实际上,ALV TREE和A ...

随机推荐

  1. TimeUnit(转)

    java.util.concurrent并发库是JDK1.5新增的,其作者是Doug Lea ,此人是个BOSS级别的天才人物了.有了他提供的类库,使得我们对多线程并发.锁有了很大的帮助,减少了并发难 ...

  2. python 用pdb调试

    简单调试 Python 程序   在 Python 中也可以像 gcc/gdb 那样调试程序,只要在运行 Python 程序时引入 pdb 模块(假设要调试的程序名为 d.py): $ vi d.py ...

  3. hadoop错误org.apache.hadoop.mapred.TaskAttemptListenerImpl Progress of TaskAttempt

    错误: org.apache.hadoop.mapred.TaskAttemptListenerImpl: Progress of TaskAttempt 原因: 错误很明显,磁盘空间不足,但郁闷的是 ...

  4. Exploring Message Brokers: RabbitMQ, Kafka, ActiveMQ, and Kestrel--reference

    [This article was originally written by Yves Trudeau.] http://java.dzone.com/articles/exploring-mess ...

  5. iOS 开发之 ReactiveCocoa(基础)

    前言 前段时间在看Masonry这个全新的第三方的布局框架的时候,开始了解了链式编程.后来慢慢的又开始了解函数式编程和响应式编程.在这集中的编程思想下,开始接触和研究了ReactiveCocoa这个框 ...

  6. Android(java)学习笔记174:SharedPreferences(轻量级存储类)

    1.SharedPreferences是Android平台上一个轻量级的存储类,简单的说就是可以存储一些我们需要的变量信息.2个activity 之间的数据传递除了可以他通过intent来传递数据,还 ...

  7. 第一篇:web之前端之html

    前端之html   前端之html 本节内容 前端概述 html结构 标签探秘 <!DOCTYPE html>标签 head标签 body标签 1.前端概述 一个web服务的组成分为前端和 ...

  8. 使用Preference保存设置

    http://blog.csdn.net/barryhappy/article/details/7381544 Android中有四种持久化数据的方法:SQLite数据库.文件存储.Preferenc ...

  9. fekit前端代码模块化工具

    fekit是一套前端开发工具,是由去哪儿网开发.目前在github上开源.使用fekit的优点: a.本地开发支持环境:从开发调试到上线,均是前后端工程独立开发.调试.部署,打破了原来前后端揉在一个工 ...

  10. CoreAnimation1-图层树、寄宿图以及图层几何学

    (一)图层的树状结构 Core Animation其实是一个令人误解的命名.你可能认为它只是用来做动画的,但实际上它是从一个叫做Layer Kit这么一个不怎么和动画有关的名字演变而来,所以做动画这只 ...