XMLHttpRequest Level 2 使用指南

http://www.ruanyifeng.com/blog/2012/09/xmlhttprequest_level_2.htmljavascript

 

XMLHttpRequest是一个浏览器接口,使得Javascript能够进行HTTP(S)通讯。php

最先,微软在IE 5引进了这个接口。由于它太有用,其余浏览器也模仿部署了,ajax操做所以得以诞生。css

可是,这个接口一直没有标准化,每家浏览器的实现或多或少有点不一样。HTML 5的概念造成后,W3C开始考虑标准化这个接口。2008年2月,就提出了XMLHttpRequest Level 2 草案。html

这个XMLHttpRequest的新版本,提出了不少有用的新功能,将大大推进互联网革新。本文就对这个新版本进行详细介绍。html5

1、老版本的XMLHttpRequest对象java

在介绍新版本以前,咱们先回顾一下老版本的用法。node

首先,新建一个XMLHttpRequest的实例。es6

  var xhr = new XMLHttpRequest();web

而后,向远程主机发出一个HTTP请求。ajax

  xhr.open('GET', 'example.php');

  xhr.send();

接着,就等待远程主机作出回应。这时须要监控XMLHttpRequest对象的状态变化,指定回调函数。

  xhr.onreadystatechange = function(){

    if ( xhr.readyState == 4 && xhr.status == 200 ) {

      alert( xhr.responseText );

    } else {

      alert( xhr.statusText );

    }

  };

上面的代码包含了老版本XMLHttpRequest对象的主要属性:

  * xhr.readyState:XMLHttpRequest对象的状态,等于4表示数据已经接收完毕。

  * xhr.status:服务器返回的状态码,等于200表示一切正常。

  * xhr.responseText:服务器返回的文本数据

  * xhr.responseXML:服务器返回的XML格式的数据

  * xhr.statusText:服务器返回的状态文本。

2、老版本的缺点

老版本的XMLHttpRequest对象有如下几个缺点:

  * 只支持文本数据的传送,没法用来读取和上传二进制文件。

  * 传送和接收数据时,没有进度信息,只能提示有没有完成。

  * 受到"同域限制"(Same Origin Policy),只能向同一域名的服务器请求数据。

3、新版本的功能

新版本的XMLHttpRequest对象,针对老版本的缺点,作出了大幅改进。

  * 能够设置HTTP请求的时限。

  * 可使用FormData对象管理表单数据。

  * 能够上传文件。

  * 能够请求不一样域名下的数据(跨域请求)。

  * 能够获取服务器端的二进制数据。

  * 能够得到数据传输的进度信息。

下面,我就一一介绍这些新功能。

4、HTTP请求的时限

有时,ajax操做很耗时,并且没法预知要花多少时间。若是网速很慢,用户可能要等好久。

新版本的XMLHttpRequest对象,增长了timeout属性,能够设置HTTP请求的时限。

  xhr.timeout = 3000;

上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动中止HTTP请求。与之配套的还有一个timeout事件,用来指定回调函数。

  xhr.ontimeout = function(event){

    alert('请求超时!');

  }

目前,Opera、Firefox和IE 10支持该属性,IE 8和IE 9的这个属性属于XDomainRequest对象,而Chrome和Safari还不支持。

5、FormData对象

ajax操做每每用来传递表单数据。为了方便表单处理,HTML 5新增了一个FormData对象,能够模拟表单。

首先,新建一个FormData对象。

  var formData = new FormData();

而后,为它添加表单项。

  formData.append('username', '张三');

  formData.append('id', 123456);

最后,直接传送这个FormData对象。这与提交网页表单的效果,彻底同样。

  xhr.send(formData);

FormData对象也能够用来获取网页表单的值。

  var form = document.getElementById('myform');

  var formData = new FormData(form);

  formData.append('secret', '123456'); // 添加一个表单项

  xhr.open('POST', form.action);

  xhr.send(formData);

6、上传文件

新版XMLHttpRequest对象,不只能够发送文本信息,还能够上传文件。

假定files是一个"选择文件"的表单元素(input[type="file"]),咱们将它装入FormData对象。

  var formData = new FormData();

  for (var i = 0; i < files.length;i++) {

    formData.append('files[]', files[i]);

  }

而后,发送这个FormData对象。

  xhr.send(formData);

7、跨域资源共享(CORS)

新版本的XMLHttpRequest对象,能够向不一样域名的服务器发出HTTP请求。这叫作"跨域资源共享"(Cross-origin resource sharing,简称CORS)。

使用"跨域资源共享"的前提,是浏览器必须支持这个功能,并且服务器端必须赞成这种"跨域"。若是可以知足上面的条件,则代码的写法与不跨域的请求彻底同样。

  xhr.open('GET', 'http://other.server/and/path/to/script');

目前,除了IE 8和IE 9,主流浏览器都支持CORS,IE 10也将支持这个功能。服务器端的设置,请参考《Server-Side Access Control》

8、接收二进制数据(方法A:改写MIMEType)

老版本的XMLHttpRequest对象,只能从服务器取回文本数据(不然它的名字就不用XML起首了),新版则能够取回二进制数据。

这里又分红两种作法。较老的作法是改写数据的MIMEType,将服务器返回的二进制数据假装成文本数据,而且告诉浏览器这是用户自定义的字符集。

  xhr.overrideMimeType("text/plain; charset=x-user-defined");

而后,用responseText属性接收服务器返回的二进制数据。

  var binStr = xhr.responseText;

因为这时,浏览器把它当作文本数据,因此还必须再一个个字节地还原成二进制数据。

  for (var i = 0, len = binStr.length; i < len; ++i) {

    var c = binStr.charCodeAt(i);

    var byte = c & 0xff;

  }

最后一行的位运算"c & 0xff",表示在每一个字符的两个字节之中,只保留后一个字节,将前一个字节扔掉。缘由是浏览器解读字符的时候,会把字符自动解读成Unicode的0xF700-0xF7ff区段。

8、接收二进制数据(方法B:responseType属性)

从服务器取回二进制数据,较新的方法是使用新增的responseType属性。若是服务器返回文本数据,这个属性的值是"TEXT",这是默认值。较新的浏览器还支持其余值,也就是说,能够接收其余格式的数据。

你能够把responseType设为blob,表示服务器传回的是二进制对象。

  var xhr = new XMLHttpRequest();

  xhr.open('GET', '/path/to/image.png');

  xhr.responseType = 'blob';

接收数据的时候,用浏览器自带的Blob对象便可。

  var blob = new Blob([xhr.response], {type: 'image/png'});

注意,是读取xhr.response,而不是xhr.responseText。

你还能够将responseType设为arraybuffer,把二进制数据装在一个数组里。

  var xhr = new XMLHttpRequest();

  xhr.open('GET', '/path/to/image.png');

  xhr.responseType = "arraybuffer";

接收数据的时候,须要遍历这个数组。

  var arrayBuffer = xhr.response;

  if (arrayBuffer) {

    var byteArray = new Uint8Array(arrayBuffer);

    for (var i = 0; i < byteArray.byteLength; i++) {

      // do something

    }
  }

更详细的讨论,请看Sending and Receiving Binary Data

9、进度信息

新版本的XMLHttpRequest对象,传送数据的时候,有一个progress事件,用来返回进度信息。

它分红上传和下载两种状况。下载的progress事件属于XMLHttpRequest对象,上传的progress事件属于XMLHttpRequest.upload对象。

咱们先定义progress事件的回调函数。

  xhr.onprogress = updateProgress;

  xhr.upload.onprogress = updateProgress;

而后,在回调函数里面,使用这个事件的一些属性。

  function updateProgress(event) {

    if (event.lengthComputable) {

      var percentComplete = event.loaded / event.total;

    }

  }

上面的代码中,event.total是须要传输的总字节,event.loaded是已经传输的字节。若是event.lengthComputable不为真,则event.total等于0。

与progress事件相关的,还有其余五个事件,能够分别指定回调函数:

  * load事件:传输成功完成。

  * abort事件:传输被用户取消。

  * error事件:传输中出现错误。

  * loadstart事件:传输开始。

  * loadEnd事件:传输结束,可是不知道成功仍是失败。

10、阅读材料

  1. Introduction to XMLHttpRequest Level 2: 新功能的综合介绍。

  2. New Tricks in XMLHttpRequest 2:一些用法的介绍。

  3. Using XMLHttpRequest:一些高级用法,主要针对Firefox浏览器。

  4. HTTP Access Control:CORS综述。

  5. DOM access control using cross-origin resource sharing:CORS的9种HTTP头信息

  6. Server-Side Access Control:服务器端CORS设置。

  7. Enable CORS:服务端CORS设置。

(完)

一灯学堂

QCon 北京2018

留言(31条)

学习了,html5的新特性真让人着迷

其实IE8,9也支持跨域资源共享,不过用的是 XDomainRequest 对象,并且作法和w3c标准不一样,不是设置在header里而是要放一个文件在服务器上(相似Flash跨域的作法)。

引用RedNax的发言:

其实IE8,9也支持跨域资源共享,不过用的是 XDomainRequest 对象,并且作法和w3c标准不一样,不是设置在header里而是要放一个文件在服务器上(相似Flash跨域的作法)。

IE8,9也支持跨域没有错,可用接口单一,可是并不须要放一个文件在服务器上,也不相似flash。

我作过测试: http://cssor.com/cross-origin-resource-sharing.html

刚看了《黑客与画家》,确实是一本不可多得的好书!

引用ToFishes的发言:

 

IE8,9也支持跨域没有错,可用接口单一,可是并不须要放一个文件在服务器上,也不相似flash。

我作过测试: http://cssor.com/cross-origin-resource-sharing.html

哦,看了一下文档确实如此。看来是我和什么混起来了……

Websocket比xhr更强大,能够实现实时的push,如今只能靠flash,随着支持浏览器的普及,将会看到更多用websocket的网站,阮先生也能够介绍一下

最近的内容涉及到好多技术的细节问题,没有太大的兴趣,固然了,写什么是阮兄的自由。

js跨域还在研究当中,学习啦

不错,假如能够顺便知道支持的浏览器的大体版本号就行了。

据我了解文中提到的“跨域资源共享(CORS)”目前仍是w3c的草案,尚未正式发布。

博主,关于CORS,最好再加上Preflighted request的内容

若是要使用除GET和POST之外的方法,或者想用content-type不是application/x-www-form-urlencoded, multipart/form-data, or text/plain 的POST,须要在request的header中添加额外的custom header

Preflighted requests

Unlike simple requests (discussed above), "preflighted" requests first send an HTTP OPTIONS request header to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data. In particular, a request is preflighted if:

It uses methods other than GET or POST. Also, if POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML payload to the server using application/xml or text/xml, then the request is preflighted.
It sets custom headers in the request (e.g. the request uses a header such as X-PINGOTHER)

https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS?redirectlocale=en-US&redirectslug=HTTP_access_control#Preflighted_requests

http://arunranga.com/examples/access-control/preflightInvocation.html

这里有很多的Demo能够参考:http://tiffanybbrown.com/presentation/2011/xhr2/

楼主您好,请问您本人是否试过XMLHttpRequest上传文件?若是有,请指教,最好是您完整的JS代码,我无恶意,经过实践以后只是对XMLHttpRequest上传文件表示质疑。毕竟他归根结底仍是一个AJAX,欢迎QQ或是邮件交流和指点,谢谢O(∩_∩)O.qq:303834036

正在学习跨文档通讯 谢谢楼主的资料0w0

引用jalorchen的发言:

楼主您好,请问您本人是否试过XMLHttpRequest上传文件?若是有,请指教,最好是您完整的JS代码,我无恶意,经过实践以后只是对XMLHttpRequest上传文件表示质疑。毕竟他归根结底仍是一个AJAX,欢迎QQ或是邮件交流和指点,谢谢O(∩_∩)O.qq:303834036

说到底,就是http协议,固然能够上传文件。 利用formdata上传过文件,将头信息更改成application/multiple,请求信息中还须要加入boundary信息,后台就能够进行解析了。后台用第三方组件解析要方便一些,我用的就是java的commonupload组件。

引用dirty的发言:

Websocket比xhr更强大,能够实现实时的push,如今只能靠flash,随着支持浏览器的普及,将会看到更多用websocket的网站,阮先生也能够介绍一下

是呀,阮老师能够介绍一下web socket.

引用dirty的发言:

Websocket比xhr更强大,能够实现实时的push,如今只能靠flash,随着支持浏览器的普及,将会看到更多用websocket的网站,阮先生也能够介绍一下

Flash的错在于它只是一个插件,小三永远转不了正。我下载新版firefox后,一启动就提示Flash崩溃,用户遇到这种状况怎么跟他解析?!

chrome 38.0已经支持xhr的timeout了

引用Thyiad的发言:


说到底,就是http协议,固然能够上传文件。
利用formdata上传过文件,将头信息更改成application/multiple,请求信息中还须要加入boundary信息,后台就能够进行解析了。后台用第三方组件解析要方便一些,我用的就是java的commonupload组件。

 


谢谢兄弟指点,我会按照您的指点尝试一下。

请问发送数据时,能否发送blob数据?文章只说了接收数据能够接收blob

谢谢阮兄,恰好要用到这个知识点!

使用阮老师提供的formData对象上传的文件(异步方式),后台(java)不知道该如何解析啊,求各位大神指点,谢谢!

谢谢楼主大大!感受收获良多!

使用起来和Android的AsyncTask挺像啊

引用山姆大叔的发言:

使用阮老师提供的formData对象上传的文件(异步方式),后台(java)不知道该如何解析啊,求各位大神指点,谢谢!

java没有像php的$_FILES类吗,同样的处理方式啊,和直接form提交没啥区别吧

引用请问阮老师的发言:

请问发送数据时,能否发送blob数据?文章只说了接收数据能够接收blob

void send();
void send(ArrayBuffer data);
void send(Blob data);
void send(Document data);
void send(DOMString? data);
void send(FormData data);

问下,关于上传进度 【event.loaded是已经传输的字节】 event里面的数据是从本地获取的仍是服务的返回的?

onreadystatechange应该在open和send以前设定吧,不然一些状态会捕捉不到

引用阮老师你好的发言:

onreadystatechange应该在open和send以前设定吧,不然一些状态会捕捉不到

如今使用onload

文件进度须要服务端支持把,能不能写几行服务端的伪代码,咱们也好理解

引用小小苏的发言:

文件进度须要服务端支持把,能不能写几行服务端的伪代码,咱们也好理解

这个应该不须要服务端支持吧

我要发表见解

相关文章
相关标签/搜索