JavaScript Ajax

XMLHttpRequest对象

  1. XHR的用法
1
2
3
4
5
// 请求类型,请求地址,是否异步
xhr.open("get","http://www.baidu/com", false)

// 作为请求主体发送的数据
xhr.send(null)
  • XHR对象的属性:
  1. responseText: 作为相应主体被返回的文本。
  2. responseXML: 如果相应的内容类型是”text/html”或”application/xml”,这个属性中将保存喊着响应数据的XML DOM文档。
  3. status: 响应HTTP状态。
  4. statusText:HTTP状态的说明。
  5. readyState:该属性表示请求/响应过程的当前活动阶段。(0未初始化,1启动,2发送,3接收,4完成)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var xhr = createXHR();

xhr.onreadystatechange = functuin () {
if (xhr.readState === 4) {
if( (xhr >= 200 && xhr.status <300) || xhr.status === 304) {
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
}
}

xhr.open("get", "example.txt", true);
xhr.send(null);

在接收响应之前还可以调用abort()方法来取消异步请求。
  1. HTTP头部信息

默认情况下,在发送XHR请求的同时,还会发送下列头部的信息:

  • Accept:浏览器能够处理的内容类型。
  • Accept-Charset:浏览器能够显示的字符集。
  • Accept-Encoding:浏览器能够处理的压缩编码。
  • Accept-Language:浏览器当前设置的语言。
  • Connection:浏览器与服务器之间连接的类型。
  • Cookie:当前页设置的任何Cookie。
  • Host:发出请求的页面所在的域。
  • Referer:发布请求的页面的URL。
  • User-Agent:浏览器的用户代理字符串。

使用setRequestHeader()方法可以设置自定义的请求头部。这个方法接受两个参数:头部字段的名称和头部字段的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
var xhr = createXHR();
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status >300) || xhr.status === 304) {
alert(xhr.responsetext)
} else {
alert("Request was unsuccessful:" + xhr.status)
}
}
}
xhr.open("get","url",true);
xhr.setRequestHeader("MyHeader","Myvalue");
xhr.send(null)

使用getErsponseHeader()方法并栓如头部字段名称,可以取得相应的响应头部信息。
使用getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。

1
2
var myHeader = xhr.getResponseHeader("MyHeader");
var allHeader = xhr.getAllResponseHeaders();
  1. Get请求

GET是最常见的请求类型,最常用于服务器查询某些信息。必要时,可以将查询字符串参数追加到URL的末尾,一遍将信息发送给服务器。对于XHR而言,位于传入open()方法的URL末尾的查询字符串必须经过正确的编码才行。

使用GET请求经常会发生一个错误,就是查询字符串的格式有问题。查询字符串中每个参数的名称和值都必须使用encodeURIComponent()进行解码,然后才能放到URL的末尾。

xhr.open('get','a.html?name=value&name1=value1',true)

addURLParam()函数

1
2
3
4
5
6
7
8
9
10
11
12
// 要添加参数的URL  参数名称  参数值
function addURLParam(url, name, value){
url += (url.indexOf("?") === -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
};

// 调用
url = addURLParam(url, "book", "张三");

// 初始化请求
xhr.open("get", url, false);
  1. POST请求

通常用于向服务器发送应该被保存的数据。POST请求应该把数据作为请求的主题提交,而GET请求传统上不是这样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function submitData(){
var xhr = createXHR();
xhr.onreadystatechange = function(){
if(xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status >300) || xhr.status === 304) {
alert(xhr.responsetext)
} else {
alert("Request was unsuccessful:" + xhr.status)
}
}
}
xhr.open("post", "example.php", true)
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
var form = document.getElementById("user-info")
xhr.send(serialize(form))
}

XMLHttpRequest 2级

  1. FormData
1
2
3
4
5
6
7
8
9
10
11
12
13
var xhr = createXHR();
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status >300) || xhr.status === 304) {
alert(xhr.responsetext)
} else {
alert("Request was unsuccessful:" + xhr.status)
}
}
}
xhr.open("post","url",true);
var form = document.getElementById("user-info")
xhr.send(new FormData(form))
  1. 超时设定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var xhr = createXHR();
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if ((xhr.status >= 200 && xhr.status >300) || xhr.status === 304) {
alert(xhr.responsetext)
} else {
alert("Request was unsuccessful:" + xhr.status)
}
}
}
xhr.open("get","url",true);
xhr.timeout = 1000;
xhr.ontimeout = function () {
alert("Request did not return is a second.");
}
xhr.send(null)
  1. overrideMimeType()方法

通过调用overrideMimeType()方法,可以保证把响应当做XML而非纯文本来处理

1
2
3
4
var xhr = createXHR();
xhr.open("get","url",true);
xhr.overrideMimeType("text/xml");
xhr.send(null);
  1. 进度事件
  • loadstart:在接收到响应数据的第一个字节是触发。
  • progress:在接收响应期间持续不断地触发。
  • error:在请求发生错误时触发。
  • abort:在因为调用abort()方法而终止连接时触发。
  • load:在接收到完整响应数据时触发。
  • loadend:在通信完成或者触发error、abort或load事件后触发。

load事件,只要浏览器接收到服务器响应,不管其状态如何,都会触发load事件。

1
2
3
4
5
6
7
8
9
10
var xhr = createXHR();
xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status >300) || xhr.status === 304) {
alert(xhr.responsetext)
} else {
alert("Request was unsuccessful:" + xhr.status)
}
}
xhr.open("get","altevents.php",true)
xhr.send(null)

progress事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var xhr = createXHR();

xhr.onload = function () {
if ((xhr.status >= 200 && xhr.status >300) || xhr.status === 304) {
alert(xhr.responsetext)
} else {
alert("Request was unsuccessful:" + xhr.status)
}
}

xhr.onprogress = function(event){
var divStatus = document.getElementById("status");
if(event.lengthComputable){
divStatus.innerHTML = "Received" + event.position + "of" + event.totalSize + "bytes";
}
}

xhr.open("get","altevents.php",true)
xhr.send(null)

跨源资源共享

CORS(Cross-Origin Resource Sharing, 跨源资源共享),是W3C的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS背后的基本思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或相应是应该成功,还是应该失败。

  • IE对CORS的实现

微软在IE8中引入了XDR(XDomainRequest)类型。这个对象与XHR类似,但能实现安全可靠的跨域通信。XDR对象的安全机制部分实现了W3C的CORS规范。以下是XDR与XHR的一些不同之处。

  1. cookie不会随请求发送,也不会随响应返回。
  2. 智能设置请求头部信息中的Content-Type字段。
  3. 不能访问响应头部信息。
  4. 只支持GET和POST请求。

这些变化使CSRF(Cross-Site Request Forgery,跨站点请求伪造)和XSS(Cross-Site Scripting,跨站点脚本)的问题得到了缓解。

被请求的资源可以根据它认为合适的任意数据(用户代理,来源页面等)来决定是否设置Access-Control-Allow-Origin头部。作为请求的一部分,Origin头部的值表示请求的来源域,以便远程 资源明确地识别XDR请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var xdr = new XDomainRequest();
xdr.onload = function(){
alert(xdr.responseText);
};
xdr.onerror = function(){
alert("An error occurred.")
};
xdr.timeout = 1000;
xdr.ontimeout = function(){
alert("Request took too long.")
}
// GET请求
xdr.open("get","url");
xdr.send(null);

// POST请求
xdr.open("post","url");
xdr.contentType = "application/x-www-form-urencoded";
xdr.send("name=value&name2=value2");

跨域XHR对象也有一些限制,但是为了安全这些限制是必需的。

  • 不能使用setRequestHeader()设置自定义头部。
  • 不能发送和接收cookie。
  • 调用getAllResponseHeaders()方法总会返回空字符串。

Preflighted Reqeusts

透明服务器验证机制支持开发人员使用自定义头部、GET或POST之外的方法,以及不同类型的主体内容。

  • Origin:与简单的请求相同。
  • Access-Control-Request-Method:请求自身使用的方法。
  • Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔。
1
2
3
Origin: url
Access-Control-Request-Method: POST
Access-Control-Request-Headers: NCZ

发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通。

1
2
3
4
Access-Control-Allow-Origin: url
Access-Control-Allow-Method: POST,GET
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000

Preflight请求结束后,结果将按照响应中指定的时间缓存起来。

带凭据的请求

默认情况下,跨源请求不提供凭据(cookie、HTTP认证及客户端SSL证明等)。通过将withCredentials属性设置为true,可以指定某个请求应该发送凭据。如果服务器接收带凭据的请求,会用下面的HTTP头部来响应。

Access-Control-Allow-Credentials: true

跨浏览器的CORS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function createCORSRequest(method,url){
var xhr = new XMLHttpRequest();
if("withCredentials" in xhr){
xhr.open(method,url,true);
}
if(typeof XDomainRequest != "undefined"){
vxhr = new XDomainRequest();
xhr.open(method, url);
}
else {
xhr = null;
}
return xhr;
}

var request = createCORSRequest("get",url);
if(request){
request.onload = function () {
// 对request.responseText进行处理
}
request.send();
}

XMLHttpRequest对象与XDomainRequest对象共同的属性/方法如下:

  • abort(): 用于停止正在进行的请求。
  • onerror: 用于替代onreadystatechange检测错误。
  • onload: 用于替代onreadystatechange检测成功。
  • responseText: 用于取得响应内容。
  • send(): 用于发送请求。

以上成员都包含在createCORSRequest()函数返回的对象中。