XMLHttpRequest详解
XMLHttpRequest的发展历程
XMLHttpRequest⼀开始只是微软浏览器提供的⼀个接⼝,后来各⼤浏览器纷纷效仿也提供了这个接⼝,再后来W3C对它进⾏了标准化,提出了。XMLHttpRequest标准⼜分为Level 1和Level 2。
XMLHttpRequest Level 1主要存在以下缺点:
受同源策略的限制,不能发送跨域请求;
不能发送⼆进制⽂件(如图⽚、视频、⾳频等),只能发送纯⽂本数据;
苏炳添是哪里人在发送和获取数据的过程中,⽆法实时获取进度信息,只能判断是否完成;
那么Level 2对Level 1进⾏了改进,XMLHttpRequest Level 2中新增了以下功能:
可以发送跨域请求,在服务端允许的情况下;
⽀持发送和接收⼆进制数据;
盆底肌训练
新增formData对象,⽀持发送表单数据;
发送和获取数据时,可以获取进度信息;
可以设置请求的超时时间;
当然更详细的对⽐介绍,可以参考,⽂章中对新增的功能都有具体代码⽰例。
花生瘦腿
XMLHttpRequest兼容性
关于xhr的浏览器兼容性,⼤家可以直接查看“Can I u”这个⽹站提供的结果,下⾯提供⼀个截图。
从图中可以看到:
IE8/IE9、Opera Mini 完全不⽀持xhr对象
IE10/IE11部分⽀持,不⽀持sponType为json
部分浏览器不⽀持设置请求超时,即⽆法使⽤xhr.timeout
部分浏览器不⽀持sponType为blob
细说XMLHttpRequest如何使⽤
先来看⼀段使⽤XMLHttpRequest发送Ajax请求的简单⽰例代码。
//发送数据
梅花手绘上⾯是⼀个使⽤xhr发送表单数据的⽰例,整个流程可以参考注释。
xhr.nd(formData);
}
接下来我将站在使⽤者的⾓度,以问题的形式介绍xhr的基本使⽤。
我对每⼀个问题涉及到的知识点都会进⾏⽐较细致地介绍,有些知识点可能是你平时忽略关注的。
如何设置request header
在发送Ajax请求(实质是⼀个请求)时,我们可能需要设置⼀些请求头部信息,⽐如content-type、connection、cookie、accept-
xxx等。xhr提供了tRequestHeader来允许我们修改请求 header。
void tRequestHeader(DOMString header, DOMString value);
注意点:
⽅法的第⼀个参数 header ⼤⼩写不敏感,即可以写成content-type,也可以写成Content-Type,甚⾄写成content-Type;
前车之鉴什么意思
Content-Type的默认值与具体发送的数据类型有关,请参考本⽂【可以发送什么类型的数据】⼀节;
tRequestHeader必须在open()⽅法之后,nd()⽅法之前调⽤,否则会抛错;
tRequestHeader可以调⽤多次,最终的值不会采⽤覆盖override的⽅式,⽽是采⽤追加append的⽅式。下⾯是⼀个⽰例代码:
鳞次栉比
var client = new XMLHttpRequest();
client.open('GET', 'i');
client.tRequestHeader('X-Test', 'one');
client.tRequestHeader('X-Test', 'two');
// 最终request header中"X-Test"为: one, two
client.nd();
如何获取respon header
xhr提供了2个⽤来获取响应头部的⽅法:getAllResponHeaders和getResponHeader。前者是获取 respon 中的所有header 字段,后者只是获取某个指定 header 字段的值。另外,getResponHeader(header)的header参数不区分⼤⼩写。
DOMString getAllResponHeaders();
DOMString getResponHeader(DOMString header);
这2个⽅法看起来简单,但却处处是坑⼉。
你是否遇到过下⾯的坑⼉?——反正我是遇到了。。。
1. 使⽤getAllResponHeaders()看到的所有respon header与实际在控制台Network中看到的respon header不⼀样
2. 使⽤getResponHeader()获取某个header的值时,浏览器抛错Refud to get unsafe header "XXX"
经过⼀番寻找最终在。
原因1:,规定客户端⽆法获取 respon 中的Set-Cookie、Set-Cookie2这2个字段,⽆论是同域还是跨域请求;
原因2:,规定对于跨域请求,客户端允许获取的respon header字段只限于“simple respon header”和“Access-Control-Expo-Headers” (两个名词的解释见下⽅)。
"simple respon header"包括的 header 字段有:Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma;
"Access-Control-Expo-Headers":⾸先得注意是"Access-Control-Expo-Headers"进⾏跨域请求时响应头部中的⼀个字段,对于同域请求,响应头部是没有这个字段的。这个字段中列举的 header 字段就是服务器允许暴露给客户端访问的字段。
所以getAllResponHeaders()只能拿到限制以外(即被视为safe)的header字段,⽽不是全部字段;⽽调⽤getResponHeader(header)⽅法时,header参数必须是限制以外的header字段,否则调⽤就会报Refud to get unsafe header的错误。
有书真好如何指定spon的数据类型
有些时候我们希望spon返回的就是我们想要的数据类型。⽐如:响应返回的数据是纯JSON字
符串,但我们期望最终通
过spon拿到的直接就是⼀个 js 对象,我们该怎么实现呢?
有2种⽅法可以实现,⼀个是level 1就提供的overrideMimeType()⽅法,另⼀个是level 2才提供的sponType属性。
xhr.overrideMimeType()
overrideMimeType是xhr level 1就有的⽅法,所以浏览器兼容性良好。这个⽅法的作⽤就是⽤来重写respon的content-type,这样做有什么意义呢?⽐如:rver 端给客户端返回了⼀份document或者是xml⽂档,我们希望最终通过spon拿到的就是⼀个DOM对象,那么就可以⽤xhr.overrideMimeType('text/xml; chart = utf-8')来实现。星座配对
再举⼀个使⽤场景,我们都知道xhr level 1不⽀持直接传输blob⼆进制数据,那如果真要传输 blob 该怎么办呢?当时就是利
⽤overrideMimeType⽅法来解决这个问题的。
下⾯是⼀个获取图⽚⽂件的代码⽰例:
代码⽰例中xhr请求的是⼀张图⽚,通过将respon的content-type改为'text/plain; chart=x-ur-defined',使得xhr以纯⽂本格式来解析接收到的blob 数据,最终⽤户通过sponText拿到的就是图⽚⽂件对应的⼆进制字符串,最后再将其转换为 blob 数据。
responType是xhr level 2新增的属性,⽤来指定spon的数据类型,⽬前还存在些兼容性问题,可以参考本⽂的【XMLHttpRequest的兼容性】这⼀⼩节。那么responType可以设置为哪些格式呢,我简单做了⼀个表,如下:
值spon数据类型说明
""String字符串默认值(在不设置responType时)
"text"String字符串
"document"Document对象希望返回XML格式数据时使⽤
"json"javascript对象存在兼容性问题,IE10/IE11不⽀持
"blob"Blob对象
"arrayBuffer"ArrayBuffer对象
下⾯是同样是获取⼀张图⽚的代码⽰例,相⽐xhr.overrideMimeType,⽤spon来实现简单得多。
var xhr = new XMLHttpRequest();
xhr.open('GET', '/path/to/image.png', true);
//可以将`sponType`设置为`"blob"`也可以设置为`" arrayBuffer"`
//sponType = 'arrayBuffer';
if (this.status == 200) {
var blob = spon;
...
}
};
xhr.nd();
⼩结
虽然在xhr level 2中,2者是共同存在的。但其实不难发现,sponType就是⽤来取
代xhr.overrideMimeType()的,sponType功能强⼤的多,xhr.overrideMimeType()能做到的sponType都能做到。所以我们现在完全可以摒弃使⽤xhr.overrideMimeType()了。
如何获取respon数据
xhr提供了3个属性来获取请求返回的数据,分别是:spon、sponText、sponXML
如何追踪ajax请求的当前状态
在发⼀个ajax请求后,如果想追踪请求当前处于哪种状态,该怎么做呢?
⽤adyState这个属性即可追踪到。这个属性是只读属性,总共有5种可能值,分别对应xhr不同的不同阶段。每次adyState的值发⽣变化时,都会触发adystatechange事件,我们可以在这个事件中进⾏相关状态判断。
adyState){
ca1://OPENED
//do something
break;
ca2://HEADERS_RECEIVED
//do something
break;
ca3://LOADING
//do something
break;
ca4://DONE
//do something
break;
}
值状态描述
0UNSENT (初始状态,未
打开)
此时xhr对象被成功构造,open()⽅法还未被调⽤
1
OPENED (已打开,未open()⽅法已被成功调⽤,nd()⽅法还未被调⽤。注意:只有xhr处于OPENED状态,才能调