XMLHttpRequest对象
- XHR的用法
1 2 3 4 5
| // 请求类型,请求地址,是否异步 xhr.open("get","http://www.baidu/com", false)
// 作为请求主体发送的数据 xhr.send(null)
|
- responseText: 作为相应主体被返回的文本。
- responseXML: 如果相应的内容类型是”text/html”或”application/xml”,这个属性中将保存喊着响应数据的XML DOM文档。
- status: 响应HTTP状态。
- statusText:HTTP状态的说明。
- 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()方法来取消异步请求。
|
- 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();
|
- 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);
|
- 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级
- 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 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)
|
- overrideMimeType()方法
通过调用overrideMimeType()方法,可以保证把响应当做XML而非纯文本来处理
1 2 3 4
| var xhr = createXHR(); xhr.open("get","url",true); xhr.overrideMimeType("text/xml"); xhr.send(null);
|
- 进度事件
- 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头部让浏览器与服务器进行沟通,从而决定请求或相应是应该成功,还是应该失败。
微软在IE8中引入了XDR(XDomainRequest)类型。这个对象与XHR类似,但能实现安全可靠的跨域通信。XDR对象的安全机制部分实现了W3C的CORS规范。以下是XDR与XHR的一些不同之处。
- cookie不会随请求发送,也不会随响应返回。
- 智能设置请求头部信息中的Content-Type字段。
- 不能访问响应头部信息。
- 只支持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()函数返回的对象中。