【JavsScript】XMLHttpRequest2的进步之处

本文参考自: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.open(‘GET‘http://www.example2.com/hello.json);

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/

时间: 2024-08-11 09:02:03

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

XMLHttpRequest2的进步之处

本文参考自:XMLHttpRequest2 新技巧 (重点保留demo,方便自己日后查阅) HTML5是现在web开发中的热点,虽然关于web app和local app一直有争论,但是从技术学习的角度,html5技术无疑是值得学习的.最近看了看XHR2,大概了解了其中比之前进步的要点,记录下来以备日后复习: 首先,XHR2的官方注解可见:http://dvcs.w3.org/hg/xhr/raw-file/tip/Overview.html XHR2主要的新功能有(我平时开发遇到的): 上传下

【JavsScript】JavaScript MVC框架PK:Angular、Backbone、CanJS与Ember

摘要:选择JavaScript MVC框架很难.一方面要考虑的因素非常多,另一方面这种框架也非常多,而要从中选择一个合适的,还真得费一番心思.本文对JavaScript MVC框架Angular.Backbone.CanJS和Ember作了比较,供大家参考. 选择JavaScript MVC框架很难.一方面要考虑的因素非常多,另一方面这种框架也非常多,而要从中选择一个合适的,还真得费一番心思.想知道有哪些JavaScript MVC框架可以选择?看看 TodoMVC吧. 我用过其中4个框架:An

【JavsScript】JavaScript MVC 框架技术选型

你很喜欢Gmail和Trello之类的单页面应用,但是不太确定该从何开始.也许你的JavaScript代码是如此的杂乱无章,以致于你很想在下一个项目上尝试下JavaScript MVC库和框架,却苦于没有头绪?我正在撰写一本单页面应用的书,所以我阅读了大量网上的相关资料.在这里我尝试提供一些看法,希望可以帮助你下决定. 简介 这里讨论的是时下最热的框架,AngularJS.Backbone.Ember和Knockout.同时提到了Batman.CANjs.Meteor和Spine,但是没有详细展

【JavsScript】推荐五款流行的JavaScript模板引擎

摘要:Javascript模板引擎作为数据与界面分离工作中最重要一环,受到开发者广泛关注.本文通过开发实例解析五款流行模板引擎:Mustache.Underscore Templates.Embedded JS Templates.HandlebarsJS.Jade templating. 近日一位20岁的开发者Jack Franklin在<The top 5 JavaScript templating engines>一文中向开发者们推荐了5款流行的JavaScript模板引擎.下面为该文的

make的特殊之处

1 规则的先后顺序问题 规则的先后顺序只会影响默认的目标,没有其它的影响. 2 make对具有相同目标的规则的处理方式 2.1 如果是单冒号 只能有一个规则是有命令的,然后对它们进行合并,即依赖合并. 2.2 如果是双冒号 分别单独处理,顺序按照makefile中的顺序.这种情况下,只有各个规则的命令是独立才是有意义的. 3 make对模式规则和非模式规则匹配的先后顺序 4 通配符扩展的时机 4.1 不会扩展的情况 第一,定义变量的时候 第二,作为函数的参数的时候 4.2 会自动扩展的情况 在命

Appcan、apicloud、HBuilder 不同之处解析

现在Hybrid app是一中非常火热的开发模式,在国内对应的开发工具也乱象丛生,有WeX5.crossApp.ExMobi.Appcan.apicloud.HBuilder等. 其中WeX5只是在PhoneGap外面套了一层壳子,内部的UI都是通过大量的css,js实现的,页面切换也大量采用webapp模式,类似于JQuery Mobile中的框架,太过偏向于webapp,性能得不到较好的体验,而且缺少第三方功能SDK封装支持. crossapp是一款实用C++开发跨平台应用的工具,因为And

传奇源码分析-客户端(游戏逻辑处理源分析四)

现在假设玩家开始操作游戏:传奇的客户端源代码工程WindHorn一.CWHApp派生CWHWindow和CWHDXGraphicWindow.二.CWHDefProcess派生出CloginProcess.CcharacterProcess.CgameProcess客户端WinMain调用CWHDXGraphicWindow g_xMainWnd;创建一个窗口.客户端CWHDXGraphicWindow在自己的Create函数中调用了CWHWindow的Create来创建窗口,然后再调用自己的C

传奇源码分析-客户端(游戏逻辑处理源分析五 服务器端响应)

器执行流程:(玩家走动) GameSrv服务器ProcessUserHuman线程处理玩家消息:遍历UserInfoList列表,依次调用每个UserInfo的Operate来处理命令队列中的所有操作; pUserInfo->Operate()调用m_pxPlayerObject->Operate()调用.判断玩家if (!m_fIsDead),如果已死,则发送_MSG_FAIL消息.我们在前面看到过,该消息是被优先处理的.否则则调用WalkTo,并发送_MSG_GOOD消息给客户端.Walk

Scala学习笔记及与Java不同之处总结-从Java开发者角度

Scala与Java具有很多相似之处,但又有很多不同.这里主要从一个Java开发者的角度,总结在使用Scala的过程中所面临的一些思维转变. 这里仅仅是总结了部分两种语言在开发过程中的不同,以后会陆续更新一些切换后在开发过程中值得注意的地方.以下列举了部分,但令人印象深刻的Scala语言的不同之处,具体的代码演示样例及具体阐述见下文. ? Scala中可直接调用Java代码,与Java无缝连接. 语句能够不用";"结束.且推荐不适用";". 变量声明时以var或va