XMLHttpRequest进行异步请求(包括文件上传)详解

Ajax是一种用脚本来发起HTTP请求与服务器进行通信的技术,能够在不刷新窗口的前提下(原始的表单提交需要刷新窗口),完成与服务器之间的交互。

概览

浏览器实现了XMLHttpRequest对象来进行异步HTTP请求,jQuery ajax是对XMLHttpRequest对象的封装。浏览器的同源策略是Ajax一个主要约束,可以同CORS、JSONP等方案来实现跨域请求。jQuery也封装了jsonp的功能,本文将会对这两种常用的异步请求方式进行全面概述。

1 XMLHttpRequest

W3C已经将XMLHttpRequest对象纳入到标准之中,1级XMLHttpRequest规范定义了XHR对象的基本功能,2级XMLHttpRequest规范进一步扩展了XHR对象。

1.1 1级XMLHttpRequest

使用流程图如下:

Created with Raphaël 2.2.0 1.创建XHR对象 var xhr = new XMLHttpRequest(); 2.指定请求的方法和url (xhr.open(type,url,Async) 3.指定请求首部 (xhr.setHeaders("Content-Type","applicationi/json")) 4.发送请求实体 (xhr.send(参数)) 5.处理响应

第二步中xhr.open需要传入三个参数

  • 第一个参数是HTTP请求的类型(GET,POST,PUT–等)
  • 第二个参数是请求的URL
  • 第三个参数布尔值,表示是异步请求(true)还是同步请求(false),默认是异步请求

第三步中指定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只能监听简单的状态变化,只能进行字符串的传输。

2级XMLHttpRequest

在XHR2中不仅能够发送文件,还能发送FormData等格式的数据,并且还增加了多个属性方法和事件,能更好的监控通信的各个环节以及有更多方式来处理响应。

2.1 新增的属性

新增了responseType属性,用于指定响应的内容类型,它和response属性组合使用,resonse根据responseType的值将响应内容解析成对应类型的值。

两者的对应关系如下表:

responseType response
“” 字符串
“text” 字符串
”arraybuffer" ArrayBuffer对象
“blob” Blob对象(File对象的基类)
“document” document对象
“json” json对象

还有三个新增的属性如下表:

属性 描述
timeout 指定一个请求的超时时间,单位为ms
upload 一个XMLHttpRequest对象,在该对象上可注册相应的事件来监控上传进度
withCredentials 在发起跨域请求的时候,是否需要携带凭据,默认为false
2.2 overrideMimeType()

能够覆盖相应报文中的Content-Type首部。

xhr.open("post","server.php");
xhr.overrideMimeType("application/xml");// 将相应的内容当作xml文档来解析
xhr.send(null);
2.3 上传文件

在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>
2.4 FormData

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类型。

2.5 终止请求和请求超时
  • 调用abort方法可以终止请求,此时会触发abort事件。
  • 当为timeout设定一个值的时候,如果请求的等待事件超过这个值,就会触发一个timeout事件。
2.6 通信进度事件

除了前面的readystatechange事件可以监听Ajax通信以外,XHR2定义了更多的有用的事件,监听通信的不同阶段。如下表

事件 描述
loadstart 请求开始,也就是调用send时触发
progress 在接受响应内容时周期性地触发,大约50ms一次
error 发送网络错误时触发,例如DNS解析错误、无限重定向等。像状态码为404、500的都不算网络错误,因此不会触发该事件
load 通信完成,也就是接收全部响应内容时触发
loadend 在load、abort、timeout和error事件之后触发
2.7 上传进度事件

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首部,还新增了多种监听事件的方法,能够动态监听上传的进度。

你可能感兴趣的:(前端)