XMLHttpRequest 对象
Ajax(即异步 JavaScript 加 XML)
,可以实现不重新加载整个网页的情况下,对网页的某部分进行更新,从而实现更好的用户体验。
把 Ajax 推到历史舞台上的关键技术是 XMLHttpRequest(XHR)对象。XHR 为发送服务器请求和获取响应提供了合理的接口。这个接口可以实现异步从服务器获取额外数据,意味着用户点击不用页面刷新也可以获取数据。通过 XHR 对象获取数据后,可以使用 DOM 方法把数据插入网页。
虽然 Ajax 这个名称中包含 XML,但实际上 Ajax 通信与数据格式无关。这个技术主要是可以实现在不刷新页面的情况下从服务器获取数据,格式并不一定是 XML。
所有现代浏览器都通过 XMLHttpRequest 构造函数原生支持 XHR 对象:
let xhr = new XMLHttpRequest();
使用 XHR
open()方法
接收 3 个参数:
-请求类型(“get”、"post"等),
-请求 URL,
-请求是否异步(布尔值)。
xhr.open("get", "url", false)
注意:
URL在这里是相对于代码所在页面的,也可以使用绝对URL。
只能访问同源 URL,也就是域名相同、端口相同、协议相同。
调用 open()不会实际发送请求,只是为发送请求做好准备
。
send()方法
接收1个参数,是作为请求体发送的数据。
如果不需要发送请求体,则必须传 null,
因为这个参数在某些浏览器中是必需
的。
xhr.send(null);
调用 send()之后,请求就会发送到服务器
。
响应数据:
因为上面这个请求是同步
的,所以 JavaScript 代码会等待服务器响应之后再继续执行。收到响应后,XHR对象的以下属性会被填充上数据。
responseText
:作为响应体返回的文本。
responseXML
:如果响应的内容类型是"text/xml"或"application/xml",那就是包含响应数据的 XML DOM 文档。
status
:响应的 HTTP 状态。 (2xx 表成功,304表资源未修改过从浏览器缓存中拿。这两种都意味着响应有效)
statusText
:响应的 HTTP 状态描述。
收到响应后,第一步要检查 status 属性以确保响应成功返回。根据status状态判断下一步操作。
虽然可以像前面的例子一样发送同步请求,但多数情况下最好使用异步请求,这样可以不阻塞
JavaScript 代码继续执行。XHR 对象有一个 readyState 属性
,表示当前处在请求/响应过程的哪个阶段。
这个属性有如下可能的值。
0:未初始化(Uninitialized)。尚未调用 open()方法。
1:已打开(Open)。已调用 open()方法,尚未调用 send()方法。
2:已发送(Sent)。已调用 send()方法,尚未收到响应。
3:接收中(Receiving)。已经收到部分响应。
4:完成(Complete)。已经收到所有响应,可以使用了。
每次 readyState 从一个值变成另一个值,都会触发 readystatechange
事件。可以借此机会检查 readyState 的值。一般来说,我们唯一关心的 readyState 值是 4
,表示数据已就绪。为保证跨浏览器兼容,onreadystatechange 事件处理程序应该在调用 open()之前赋值。来看下面的例子:
let xhr = new XMLHttpRequest();
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.send(null);
在收到响应之前如果想取消异步请求,可以调用 abort()方法:
xhr.abort();
调用这个方法后,XHR 对象会停止触发事件,并阻止访问这个对象上任何与响应相关的属性。中断请求后,应该取消对 XHR 对象的引用。由于内存问题,不推荐重用 XHR 对象
HTTP 头部
默认情况下,XHR 请求会发送以下头部字段。
Accept:浏览器可以处理的内容类型。
Accept-Charset:浏览器可以显示的字符集。
Accept-Encoding:浏览器可以处理的压缩编码类型。
Accept-Language:浏览器使用的语言。
Connection:浏览器与服务器的连接类型。
Cookie:页面中设置的 Cookie。
Host:发送请求的页面所在的域。
Referer:发送请求的页面的 URI。
User-Agent:浏览器的用户代理字符串。
如果需要发送额外的请求头部
,可以使用 setRequestHeader()
方法。
这个方法接收两个参数:头部字段的名称和值。
为保证请求头部被发送,必须在 open()之后、send()之前调用 setRequestHeader(),在上面例子中优化:
xhr.open("get", "url", true);
xhr.setRequestHeader("MyHeader", "MyValue");
xhr.send(null);
可以使用 getResponseHeader()方法从 XHR 对象获取响应头部
,只要传入要获取头部的名称即
可。如果想取得所有响应头部,可以使用 getAllResponseHeaders()方法,这个方法会返回包含所
有响应头部的字符串。下面是调用这两个方法的例子
let myHeader = xhr.getResponseHeader("MyHeader");
let allHeaders xhr.getAllResponseHeaders();
GET 请求
最常用的请求方法是 GET 请求,用于向服务器查询某些信息。可以选择是否传参。
传参格式
:
发送 GET 请求最常见的一个错误是查询字符串格式不对。
查询字符串中的所有名/值对必须以和号(&)分隔,如下面的例子所示:
xhr.open("get", "url?name1=value1&name2=value2", true);
POST 请求
第二个最常用的请求是 POST 请求,用于向服务器发送应该保存的数据。每个 POST 请求都应该在请求体中携带提交的数据。
xhr.open("post", "url", true)
接下来就是要给 send()方法传入要发送的数据。因为 XHR 最初主要设计用于发送 XML,所以可以传入序列化之后的 XML DOM 文档作为请求体
。当然,也可以传入任意字符串。
默认情况下,对服务器而言,POST 请求与提交表单是不一样的。服务器逻辑需要读取原始 POST数据才能取得浏览器发送的数据。不过,可以使用 XHR 模拟表单提交。为此,第一步需要把 Content-Type 头部设置为"application/x-www-formurlencoded",这是提交表单时使用的内容类型。第二步是创建对应格式的字符串。POST 数据此时使用与查询字符串相同的格式。如果网页中确实有一个表单需要序列化并通过 XHR 发送到服务器,则可以使serialize()函数来创建相应的字符串,如下所示:
xhr.open("post", "url", true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
let form = document.getElementById("user-info");
xhr.send(serialize(form));
ID 为"user-info"的表单中的数据被序列化之后发送给了服务器。
FormData 类型
XMLHttpRequest Level 2 新增了FormData 类型。FormData 类型便于表单序列化,也便于创建与表单类似格式的数据然后通过 XHR发送。
创建了一个 FormData 对象,并填充了一些数据:
let data = new FormData();
data.append("name", "Nicholas");
data.append("age", 12);
append()方法接收两个参数:键和值,相当于表单字段名称和该字段的值。可以像这样添加任意多个键/值对数据。
有了 FormData 实例,可以像下面这样直接传给 XHR 对象的 send()方法:
xhr.open("post", "url", true);
let form = document.getElementById("user-info");
xhr.send(new FormData(form)); //不再需要给 XHR 对象显式设置任何请求头部了