Ajax是一种用脚本来发起HTTP请求与服务器进行通信的技术,能够在不刷新窗口的前提下(原始的表单提交需要刷新窗口),完成与服务器之间的交互。
浏览器实现了XMLHttpRequest对象来进行异步HTTP请求,jQuery ajax是对XMLHttpRequest对象的封装。浏览器的同源策略是Ajax一个主要约束,可以同CORS、JSONP等方案来实现跨域请求。jQuery也封装了jsonp的功能,本文将会对这两种常用的异步请求方式进行全面概述。
W3C已经将XMLHttpRequest对象纳入到标准之中,1级XMLHttpRequest规范定义了XHR对象的基本功能,2级XMLHttpRequest规范进一步扩展了XHR对象。
使用流程图如下:
第二步中xhr.open需要传入三个参数
第三步中指定HTTP的请求首部,可以多次调用设置多个请求头。但是像Content-Length、Data、Cookie和User-Agent等首部无法自定义,为了安全,防止服务器收到伪造请求。
第四步中发送实体请求,如果是GET请求,那么就传递null或省略方法的参数,因为GET请求的内容将作为URL的查询字符串发送给服务器(意思就是将参数放到URL中)。可以发送字符串、json字符串、XML格式的文档。xhr2中还可以发送File,FormData,Blob等对象。
第五步处理响应,一个HTTP响应包括响应的状态码、响应首部和响应实体,可以通过xhr对象的属性和方法来获取到这些信息。当响应完成时,会触发readystatechange事件,为了保证浏览器的兼容性,一般在open方法之前注册
示例如下:
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
xhr.statusText; // 原因短语,如果status==200则为ok
xhr.responseText; // 响应字符串
xhr.getResponseHeader("Content-Type");
xhr.getAllResponseHeaders();
}
}
}
xhr的readyStatus属性的值是一个数字,标识通信的状态,取值如下表
属性值 | 含义 |
---|---|
0 | 未打开,尚未调用open方法 |
1 | 未发送,已调用open方法,但未调用send方法 |
2 | 已发送,已调用send方法,且已经接收到响应首部 |
3 | 接收中,响应内容下载中,接收到部分 |
4 | 完成,已接收全部内容 |
1级XMLHttpRequest只能监听简单的状态变化,只能进行字符串的传输。
在XHR2中不仅能够发送文件,还能发送FormData等格式的数据,并且还增加了多个属性方法和事件,能更好的监控通信的各个环节以及有更多方式来处理响应。
新增了responseType属性,用于指定响应的内容类型,它和response属性组合使用,resonse根据responseType的值将响应内容解析成对应类型的值。
两者的对应关系如下表:
responseType | response |
---|---|
“” | 字符串 |
“text” | 字符串 |
”arraybuffer" | ArrayBuffer对象 |
“blob” | Blob对象(File对象的基类) |
“document” | document对象 |
“json” | json对象 |
还有三个新增的属性如下表:
属性 | 描述 |
---|---|
timeout | 指定一个请求的超时时间,单位为ms |
upload | 一个XMLHttpRequest对象,在该对象上可注册相应的事件来监控上传进度 |
withCredentials | 在发起跨域请求的时候,是否需要携带凭据,默认为false |
能够覆盖相应报文中的Content-Type首部。
xhr.open("post","server.php");
xhr.overrideMimeType("application/xml");// 将相应的内容当作xml文档来解析
xhr.send(null);
在XHR2中,允许给send方法传递一个File对象实现文件上传。通过File元素files属性就可以获取一个file对象。这种情况下,如果没有显示的指定Content-Type,XHR2会根据File对象的type属性自动设置Content-Type首部。
<input type="file" id="upload"/>
<script>
var input = document.getElementById("upload");
input.addEventListener("change",function() {
var file = this.files[0];
var xhr = new XMLHttpRequest();
xhr.open("post","server.php");
xhr.send(file);
},false); // 第三个参数false指在冒泡阶段触发响应函数
script>
XHR2定义了一种全新的FormData类型,当给send方法传递该类型的数据时,能够进行一次multipart/form-data编码的HTTP请求,即模拟一次表单请求。
它的用法也非常简单:
var data = new FormData();
var input = document.getElementById("upload");
data.append("id",1);
data.append("upload",input.files[0]);
var xhr = new XMLHttpRequest();
xhr.open("post","server.php");
xhr.send(data);
formdata可以组织多种不同的数据类型同时上传,如上例中中同时发送字符串和文件。然后XHR2会自动设置请求的Content-Type类型。
除了前面的readystatechange事件可以监听Ajax通信以外,XHR2定义了更多的有用的事件,监听通信的不同阶段。如下表
事件 | 描述 |
---|---|
loadstart | 请求开始,也就是调用send时触发 |
progress | 在接受响应内容时周期性地触发,大约50ms一次 |
error | 发送网络错误时触发,例如DNS解析错误、无限重定向等。像状态码为404、500的都不算网络错误,因此不会触发该事件 |
load | 通信完成,也就是接收全部响应内容时触发 |
loadend | 在load、abort、timeout和error事件之后触发 |
XHR2提供了监控上传内容的事件,在实现该特性的浏览器中,XHR2对象会包含一个upload属性,该属性保存了一个XMLHttpRequestUpload对象,相关的监控事件都注册在该对象上。例如可以用process事件来计算当前上传内容的比例。如下例:
xhr.upload.onprocess = function(event){ // event包含两个只读属性,loaded和total
var per = Math.round(event.loaded/event.total*100);
console.log(per);
}
1级XMLHttpRequest只定义了简单的通信状态检测方法,只能传输字符串类型。
而2级XMLHttpRequest可以传输字符串、文件、表单等多种格式的数据,且能够根据资源类型自动设置Content-Type首部,还新增了多种监听事件的方法,能够动态监听上传的进度。