就叫 Ajax,即 Asynchronous JavaScript + XML ,异步JS+XML。
这一技术能够向服务器请求额外的数据而无须卸载页面。改变自从 Web 诞生以来就一直沿用的“单击,等待”的交互模式。
Ajax 技术的核心是 XMLHttpRequest 对象(简称 XHR),XHR 为向服务器发送请求和解析服务器响应提供了流畅的接口。能够以异步方式从服务器取得信息,意味着用户单击后,可以不必刷新页面也能取得新数据。 也就是说,可以使用 XHR 对象取得新数据,然后再通过 DOM 将新数据插入到页面中。
另外,虽然名字中包含 XML 的成分,但 Ajax 通信与数据格式无关;这种技术就是无须刷新页面即可从服务器取得数据,但不一定是 XML 数据。
XMLHttpRequest对象
IE7+、Firefox、Opera、Chrome 和 Safari 都支持原生的 XHR 对象,在这些浏览器中创建 XHR 对象要像下面这样使用 XMLHttpRequest 构造函数。
var xhr = new XMLHttpRequest();
XHR的用法
在使用 XHR 对象时,要调用的第一个方法是 open(),它接受 3 个参数:
1、要发送的请求的类型(“get”、”post”等)
2、请求的 URL
3、是否异步发送请求的布尔值。
下面就是调用这个方法的例子。
xhr.open("get","example.PHP",false);
这行代码会启动一个针对 example.PHP 的 GET 请求。
有关这行代码,需要说明两点:一是 URL 是相对路径,它相对于于执行代码的当前页面(当然也可以使用绝对路径);二是调用 open()方法并不会真正发送请求, 而只是启动一个请求以备发送。
并且, 只能向同一个域中使用相同端口和协议的 URL 发送请求。如果 URL 与启动请求的页面的域有任何差别,都会引发安全错误。也就是说,跨域问题是Ajax的短板。
xhr.open("get","example.txt",false);
xhr.send(null);
这里的 send() 方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入 null,因为这个参数对有些浏览器来说是必需的。
调用 send()之后,请求就会被分派到服务器。
在收到服务器的响应后,响应的数据会自动填充 XHR 对象的属性,相关的属性简介如下:
1. responseText:作为响应主体被返回的文本。
2. responseXML:如果响应的内容类型是”text/xml”或”application/xml”,这个属性中将保存包含着响应数据的 XML DOM 文档。
3. status:响应的 HTTP 状态。
4. statusText:HTTP 状态的说明。
在接收到响应后,第一步是检查 status 属性,以确定响应已经成功返回。
一般来说,可以将 HTTP 状态代码为 200 作为成功的标志。此时,responseText 属性的内容已经就绪,而且在内容类型正确的情况下,responseXML 也应该能够访问了。
此外,状态代码为 304 表示请求的资源并没有被修改,可以直接使用浏览器中缓存的版本;当然,也意味着响应是有效的。
为确保接收到适当的响应,应该像下面这样检查上述这两种状态代码:
if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304){
alert(xhr.responseText);
} else {
alert("Request was unsuccessful: " + xhr.status);
}
注意:无论内容类型是什么,响应主体的内容都会保存到 responseText 属性中;而对于非 XML 数据而言,responseXML 属性的值将为 null。
多数情况下,我们要发送的是异步请求,这样才能让 JavaScript 继续执行而不必等待响应。此时,可以检测 XHR 对象的 readyState 属性,该属性表示请求/响应过程的当前活动阶段。
这个属性可取的值如下。
0:未初始化。尚未调用 open()方法。
1:启动。已经调用 open()方法,但尚未调用 send()方法。
2:发送。已经调用 send()方法,但尚未接收到响应。
3:接收。已经接收到部分响应数据。
4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
只要 readyState 属性的值由一个值变成另一个值,都会触发一次 readystatechange 事件。可以利用这个事件来检测每次状态变化后 readyState 的值。通常,我们只对 readyState 值为 4 的阶段感兴趣,因为这时所有数据都已经就绪。
最好在调用 open()之前指定 onreadystatechange 事件处理程序,这样可以确保跨浏览器兼容性。
另外,在接收到响应之前还可以调用 abort()方法来取消异步请求,如下所示:
xhr.abort();
调用这个方法后,XHR 对象会停止触发事件,而且也不再允许访问任何与响应有关的对象属性。在 终止请求之后,还应该对 XHR 对象进行解引用操作。
HTTP头部信息
默认情况下,在发送 XHR 请求的同时,还会发送下列头部信息。
Accept:浏览器能够处理的内容类型。
Accept-Charset:浏览器能够显示的字符集。
Accept-Encoding:浏览器能够处理的压缩编码。
Accept-Language:浏览器当前设置的语言。
Connection:浏览器与服务器之间连接的类型。
Cookie:当前页面设置的任何 Cookie。
Host:发出请求的页面所在的域 。
Referer:发出请求的页面的 URI。注意,HTTP 规范将这个头部字段拼写错了,而为保证与规
范一致,也只能将错就错了。(这个英文单词的正确拼法应该是 referrer。)
User-Agent:浏览器的用户代理字符串。
虽然不同浏览器实际发送的头部信息会有所不同,但以上列出的基本上是所有浏览器都会发送的。
使用 setRequestHeader()方法可以设置自定义的请求头部信息。这个方法接受两个参数:头部字段的名称和头部字段的值。要成功发送请求头部信息,必须在调用 open()方法之后且调用 send()方法之前调用 setRequestHeader()。
xhr.open("get",true);
xhr.setRequestHeader("MyHeader","MyValue");
xhr.send(null);
我们建议读者使用自定义 的头部字段名称,不要使用浏览器正常发送的字段名称,否则有可能会影响服务器的响应。
此外,有的浏览器允许开发人员重写默认的头部信息,但有的浏览器则不允许这样做。
调用 XHR 对象的 getResponseHeader()方法并传入头部字段名称,可以取得相应的响应头部信息。而调用 getAllResponseHeaders()方法则可以取得一个包含所有头部信息的长字符串。
GET请求
GET 是最常见的请求类型,最常用于向服务器查询某些信息。
必要时,可以将查询字符串参数追加到 URL 的末尾,以便将信息发送给服务器。对 XHR 而言,位于传入 open()方法的 URL 末尾的查询字符串必须经过正确的编码才行。
//编码函数
function addURLParam(url,name,value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
POST请求
使用频率仅次于 GET 的是 POST 请求,通常用于向服务器发送应该被保存的数据。
POST 请求应该把数据作为请求的主体提交,而 GET 请求传统上不是这样。POST 请求的主体可以包含非常多的数据, 而且格式不限。在 open()方法第一个参数的位置传入”post”,就可以初始化一个 POST 请求。
发送 POST 请求的第二步就是向 send() 方法中传入某些数据。由于 XHR 最初的设计主要是为了处理 XML,因此可以在此传入 XML DOM 文档,传入的文档经序列化之后将作为请求主体被提交到服务器。
当然,也可以在此传入任何想发送到服务器的字符串。
//使用 XHR 来模仿表单提交
xhr.open("post","postexample.PHP",true);
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
var form = document.getElementById("user-info");
xhr.send(serialize(form));
XMLHttpRequest 2 级
XMLHttpRequest 2 级则进一步发展了 XHR。并非所有浏览器都完整地实现了 XMLHttpRequest 2 级规范,但所有浏览器都实现了它规定的部分内容。
FormData
FormData 为序列化表单以及创建与表单格式相同的数据(用于通过 XHR 传输)提供了便利。
可以以键值对的方式向FormData对象中注入数据:
var data = new FormData();
data.append("name","Nicholas");
而通过向 FormData 构造函数中传入表单元素,可以利用表单元素的数据向其中填入键值对儿:
var data = new FormData(document.forms[0]);
创建了 FormData 的实例后,就可以将它直接传给 XHR 的 send() 方法。
var form = document.getElementById("user-info");
xhr.send(new FormData(form));
使用 FormData 的方便之处体现在,不必像使用serialize方法时那样在 XHR 对象上设置请求头部。XHR 对象能够识别传 入的数据类型是 FormData 的实例,并配置适当的头部信息。
进度事件
这些进度事件都是和客户端与服务器通信状态有关的事件,最早其实只针对 XHR 操作,但目前也被其他 API 借鉴。这些事件共有6个,如下所列:
- loadstart:在接收到响应数据的第一个字节时触发。
- progress:在接收响应期间持续不断地触发。
- error:在请求发生错误时触发。
- abort:在因为调用 abort() 方法而终止连接时触发。
- load:在接收到完整的响应数据时触发。
- loadend:在通信完成或者触发 error、abort 或 load 事件后触发。
每个请求都从触发 loadstart 事件开始,接下来是一或多个 progress 事件,然后触发 error、abort 或 load 事件中的一个,最后以触发 loadend 事件结束。
支持前 5 个事件的浏览器有 Firefox 3.5+、Safari 4+、Chrome、iOS 版 Safari 和 Android 版 WebKit。
Opera(从第 11 版开始)、IE 8+只支持 load 事件。目前还没有浏览器支持 loadend 事件。
跨源资源共享
默认情况下,XHR 对象只能访问与包含它的页面位于同一个域中的资源。这种安全策略可以预防某些恶意行为。但是,实现合理的跨域请求对开发某些浏览器应用程序也是至关重要的。
(待续)