本章内容
- 使用
XMLHttpRequest
对象 - 使用
XMLHttpRequest
事件 - 跨域 Ajax 通信的限制
Ajax 技术的核心是 XMLHttpRequest
对象(简称 XHR)。
21.1 XMLHttpRequest 对象
var xhr = new XMLHttpRequest();
21.1.1 XHR 的用法
在使用 XHR 对象时,要调用的第一个方法是open()
,以启动一个请求以备发送,它接受 3 个参数:要发送的请求类型,请求的 URL 和表示是否异步发送请求的布尔值。
xhr.open("get", "example.php", false);
只能向同一个域中使用相同端口和协议的 URL 发送请求。如果 URL 与启动请求的页面有任何差别,都会引发安全错误。
要发送特定的请求,必须像下面这样调用send()
方法:
xhr.open("get", "example.txt", false);
xhr.send(null);
这里的send()
方法接收一个参数,即要作为请求主体发送的数据。如果不需要通过请求主体发送数据,则必须传入null
,因为这个参数对有些浏览器来说是必需的。调用send()
后,请求就会被分派到服务器。
在收到响应后,响应的数据会自动填充 XHR 对象的属性,相关的属性简介如下。
-
responseText
:作为响应主体被返回的文本 -
responseXML
:如果响应的内容类型是"text/xml"
或"application/xml"
,这个属性中将保存包含着响应数据的 XML DOM 文档。 -
status
:响应的 HTTP 状态。 -
statusText
:HTTP 状态的说明。
为确保接收适当的响应,应该像下面这样检查上述这两种状态代码:
xhr.open("get", "example.txt", false);
xhr.send(null);
if((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
alert(xhr.responseText);
} else {
alert("request was unsuccessful:" + xhr.status);
}
多数情况下,需要发送异步请求,才能让 JavaScript 继续执行而不必等待响应。此时,可以检测 XHR 对象的readyState
属性,该属性表示请求/响应过程的当前活动阶段。这个属性可取的值如下。
- 0:未初始化。尚未调用
open()
方法。 - 1:启动。已经调用
open()
方法,但尚未调用send()
方法。 - 2:发送。已经调用
send()
方法,但尚未接收到响应。 - 3:接收。已经接收到部分响应数据。
- 4:完成。已经接收到全部响应数据,而且已经可以在客户端使用了。
readyState
属性值变化时,会触发readystatechange
事件
。通常,我们只对readyState
值为 4 的阶段感兴趣,因为这时所有数据都已经就绪。
var xhr = createXHR();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if ((xhr.state >= 200 && xhr.state.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()
方法来取消异步请求。
xhr.abort();
21.1.2 HTTP 头部信息
每个 HTTP 请求和响应都会带有相应的头部信息,其中有的对开发人员有用,有的也没有什么用。
XHR
对象提供了操作这两种头部信息的方法。
默认情况下,在发送XHR
请求的同时,还会发送下列头部信息(略)。
使用setRequestHeader()
方法可以设置自定义的请求头部信息。必须在调用open()
方法之后且调用send()
方法之前调用setRequestHeader()
。
调用XHR
对象的getResponseHeader()
方法并传入头部字段名称,可以取得相应的响应头部信息。
21.1.3 GET 请求
查询字符串中每个参数的名称和值都必须使用encodeURIComponent()
进行编码,然后才能放到 URL 的末尾;而且所有名-值对都必须由和号分隔。
下面这个函数可以辅助向现有 URL 的末尾添加查询字符串参数:
function addURLParam(url, name, value) {
url += (url.indexOf("?") == -1 ? "?" : "&");
url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
return url;
}
21.2.4 POST 请求
21.2 XMLHttpRequest 2 级
21.2.1 FormData
21.2.2 超时设定
21.2.3 overrideMimeType() 方法
21.3 进度事件
21.3.1 load 事件
21.3.2 progress 事件
21.4 跨源资源共享
21.4.1 IE 对 CORS 的实现
21.4.2 其他浏览器对 CORS 的实现
使用标准的 XHR 对象并在open()
方法中传入绝对 URL 即可。
跨域 XHR 对象也有一些限制。
- 不能使用
setRequestHeader()
设置自定义头部。 - 不能发送和接收 cookie。
- 调用
getAllResponseHeaders()
方法总会返回空字符串。
21.4.3 Preflighted Requests
21.4.4 带凭据的请求
21.4.5 跨浏览器的 CORS
21.5 其他跨域技术
21.5.1 图像 Ping
21.5.2 JSONP
21.5.3 Comet
Comet 是一种更高级的 Ajax 技术(“服务器推送”)。Comet 则是一种服务器向页面推送数据的技术。能够让信息几乎实时地被推送到页面上,非常适合处理体育比赛的分数和股票报价。
有两种实现 Comet 的方式:长轮询和流。长轮询是传统轮询的一个翻版,即浏览器定时向服务器发送请求,看有没有更新的数据。
长轮询把短轮询颠倒了一下。页面发起一个服务器的请求,然后服务器一直保持连接打开,直到有数据可发送。发送完数据之后,浏览器关闭连接,随即又发起一个到服务器的新请求。这一过程在页面打开期间一直持续不断。
轮询的优势是所有浏览器都支持,因为使用 XHR 对象和setTimeout()
就能实现。而你要做的就是决定什么时候发送请求。
第二种是 HTTP 流。它在页面的整个生命周期内只使用一个 HTTP 连接。具体来说,就是浏览器向服务器发送一个请求,就是浏览器向服务器发送一个请求,而服务器保持连接打开,然后周期性地向浏览器发送数据。
所有服务器端语言都支持打印到输出缓存然后刷新(将输出缓存中的内容一次性全部发送到客户端)的功能。而这正是实现 HTTP 流的关键所在。
通过侦听readystatechange
事件及检测readyState
的值是否为 3,就可以利用 XHR 对象实现 HTTP 流。
21.5.4 服务器发送事件
SSE(Server-Sent Events, 服务器发送事件)是围绕只读 Comet 交互推出的 API 或者模式。SSE API 用于创建到服务器的单向连接,服务器通过这个连接可以发送任意数量的数据。
21.5.5 Web Sockets
目标是在一个单独的持久连接上提供全双工、双向通信。
21.5.6 SSE 与 Web Sockets
21.6 安全
为确保通过 XHR 访问的 URL 安全,通行的做法就是验证发送请求者是否有权限访问相应的资源。
有下列几种方式可供选择
- 要求以 SSL 连接来访问可以通过 XHR 请求的资源。
- 要求每一次请求都要附带经过相应算法计算得到的验证码。
21.7 小结
Ajax 是无需刷新页面就能够从服务器取得数据的一种方法。