手写一个Ajax请求
手写一个Ajax请求
前面我们讲到了XMLHttpRequest的属性、方法和事件。也聊到了很多纯原生写法上需要注意的点,这是我们使用第三方库时常常忽略的。可是,说了再多也不如亲手试试,今天我们就来使用纯原生的方式写一个Ajax请求。
首先说明,由于DOM 2级的扩展,Ajax请求监听方式多了很多方式,我们今天实现的是目前现代浏览器都能支持的方式,不考虑较早版本的兼容问题。所以这里我讲主要使用以下几个属性、方法和事件。
属性
- status
- responseType
- response
- responseText
- responseXML
- responseURL
- timeout
方法
- open
- send
- setRequestHeader
- getRequestHeader
- getAllResponseHeader
- overrideMimeType
事件
- onloadstart
- onload
- onloadend
- onerror
- onabort
- ontimeout
第一步,创建一个XHR实例
编写Ajax的第一步自然是需要创建一个XHR实例。
// 创建一个xhr实例
var xhr = new XMLHttpRequest()
第二步,绑定XHR相关的事件
为了尽可能的兼容所有浏览器,最好将事件绑定放在open方法之前。
xhr.onloadstart = function () {
// 当数据开始下载的第一刻,触发该事件
}
xhr.onprogress = function() {
// 当数据开始下载时,反复触发该事件
// 由于TCP请求会造成切片分包发送的情况,每个分包下载完成时都会触发该事件
// 如果数据量较小,则不会存在切片分包情况,该事件将只会触发一次
}
xhr.onload = function () {
// 如果所有分片数据都接收完成,触发该事件
}
xhr.onloadend = function () {
// 请求完成时(无论成功还是失败),触发该事件
}
xhr.onerror = function () {
// 当请求发生错误时,触发该事件
}
xhr.onabort = function () {
// 当请求被主动取消时,触发该事件
}
xhr.ontimeout = function () {
// 如果xhr实例设置了timeout,且请求时间超过了timeout设置的超时时间,触发该事件
}
第三步,准备请求
调用open方法后,发送请求已经做好了准备,这时候随时可以执行发送操作
// 包含三个参数:请求的方法、请求的url(可以是相对的,也可以是绝对的)、是否异步
xhr.open('GET', 'https://w2.test.com/api/test/index', true)
第四步,设置额外配置
在open方法执行之后,我们可以对xhr对象设置属性、添加请求头以及强制设置返回的Content-Type
// 请求超过20秒未响应之后,执行超时操作
xhr.timeout = 20000
// 根据该属性可以帮助response属性正确解析响应内容
xhr.responseType = "blob"
// 可以向跨域请求发送Cookies、额外的请求头或者TLS客户端证书等信息
xhr.withCredentials = true
// 设置额外的请求头
xhr.setRequestHeader('x-token', 'authorize-token')
// 强制设定MIME,帮助浏览器更好地解析响应数据
xhr.overrideMimeType('text/plain')
第五步,发送请求
在这些操作全部完成之后,可以调用send方法发送请求。
// 如果是POST请求,send方法的第一个参数为要发送的载荷
// 如果是GET请求,第一个参数传null(为了兼容所有浏览器)
xhr.send(null)
完整例子
var xhr = new XMLHttpRequest()
xhr.onloadstart = function () {
// 当数据开始下载的第一刻,触发该事件
}
xhr.onprogress = function() {
// 当数据开始下载时,反复触发该事件
// 由于TCP请求会造成切片分包发送的情况,每个分包下载完成时都会触发该事件
// 如果数据量较小,则不会存在切片分包情况,该事件将只会触发一次
}
xhr.onload = function () {
// 如果所有分片数据都接收完成,触发该事件
// 在这里可以调用getAllResponseHeaders方法来获取请求头字符串
var headers = xhr.getAllResponseHeaders()
var arr = headers.trim().split(/[\r\n]+/);
var headerMap = {};
arr.forEach(function (line) {
var parts = line.split(': ');
var header = parts.shift();
var value = parts.join(': ');
headerMap[header] = value;
});
}
xhr.onloadend = function () {
// 请求完成时(无论成功还是失败),触发该事件
}
xhr.onerror = function () {
// 当请求发生错误时,触发该事件
}
xhr.onabort = function () {
// 当请求被主动取消时,触发该事件
}
xhr.ontimeout = function () {
// 如果xhr实例设置了timeout,且请求时间超过了timeout设置的超时时间,触发该事件
}
xhr.open('GET', 'https://w2.test.com/api/test/index', true)
xhr.timeout = 20000
xhr.responseType = "blob"
xhr.withCredentials = true
xhr.setRequestHeader('x-token', 'authorize-token')
xhr.overrideMimeType('text/plain')
xhr.send(null)