XMLHttpRequest(XHR)简介
这篇文章最初发表在attacomsian.com/blog上。
XMLHttpRequest (XHR) 由微软于 20 世纪 90 年代初发明,并在 21 世纪第一个十年中期成为异步服务器交互的首选技术。
得益于 XHR,我们第一次可以在不重新加载整个页面的情况下更新网页的部分内容。
XMLHttpRequest
是所有现代浏览器中的内置浏览器对象,可用于在 JavaScript 中发出 HTTP 请求以在 Web 浏览器和服务器之间交换数据。
尽管名称中带有“XML”一词,但它XMLHttpRequest
可以用于检索任何类型的数据,而不仅仅是XML。我们可以使用它来上传/下载文件、提交表单数据、跟踪进度等等。
基本 XHR 请求
要使用 XHR 发送 HTTP 请求,请创建一个XMLHttpRequest
对象,打开与 URL 的连接,然后发送请求。请求完成后,该对象将包含有用的信息,例如响应主体和 HTTP 状态代码。
让我们使用JSONPlaceholder测试 REST API 来通过 XHR 发送 GET 请求:
// create an XHR object
const xhr = new XMLHttpRequest();
// listen for `onload` event
xhr.onload = () => {
// process response
if (xhr.status == 200) {
// parse JSON data
console.log(JSON.parse(xhr.response));
} else {
console.error('Error!');
}
};
// create a `GET` request
xhr.open('GET', 'https://jsonplaceholder.typicode.com/users');
// send request
xhr.send();
xhr.onload
event 仅适用于现代浏览器(IE10+、FireFox、Chrome、Safari)。如果您想支持旧版浏览器,请使用xhr.onreadystatechange
event。
xhr.open()
方法
在上面的示例中,我们将 HTTP 方法和 URL 传递给了请求 toopen()
方法。此方法通常在 之后立即调用new XMLHttpRequest()
。我们可以使用此方法指定请求的主要参数:
该方法的语法如下:
xhr.open(method, URL, [async, user, password])
method
— HTTP 请求方法。可以是GET
、POST
、、 等DELETE
。PUT
URL
— 请求的 URL,字符串或URL 对象asnyc
— 指定请求是否异步进行。默认值为true
username
&password
——基本 HTTP 身份验证的凭证
该open()
方法不会打开与 URL 的连接。它仅配置 HTTP 请求。
xhr.send()
方法
xhr.send([body])
该send()
方法会打开网络连接并向服务器发送请求。它接受一个body
包含请求主体的可选参数。对于像 这样的请求方法,GET
您无需传递 body 参数。
XHR 事件
最广泛使用的三种 XHR 事件如下:
load
— 当结果准备就绪时调用此事件。它相当于xhr.onreadystatechange
带有 的事件xhr.readyState == 4
。error
— 当由于网络故障或 URL 无效而导致请求失败时,会触发此事件。progress
— 此事件在响应下载期间定期触发。它可用于报告大型网络请求的进度。
// listen for `load` event
xhr.onload = () => {
console.log(`Data Loaded: ${xhr.status} ${xhr.response}`);
};
// listen for `error` event
xhr.onerror = () => {
console.error('Request failed.');
}
// listen for `progress` event
xhr.onprogress = (event) => {
// event.loaded returns how many bytes are downloaded
// event.total returns the total number of bytes
// event.total is only available if server sends `Content-Length` header
console.log(`Downloaded ${event.loaded} of ${event.total}`);
}
请求超时
您可以通过指定毫秒的时间轻松配置请求超时:
// set timeout
xhr.timeout = 5000; // 5 seconds
// listen for `timeout` event
xhr.ontimeout = () => console.log('Request timeout.', xhr.responseURL);
xhr.responseURL
属性返回实例在完成所有重定向后的最终 URLXMLHttpRequest
。这是检索标头的唯一方法Location
。
响应类型
我们可以使用xhr.responseType
属性来设置预期的响应格式:
- 空(默认)或
text
纯文本 json
— 解析后的 JSONblob
— 二进制数据 Blobdocument
— XML 文档arraybuffer
—ArrayBuffer
对于二进制数据
让我们调用 RESTful API 来获取 JSON 格式的响应:
const xhr = new XMLHttpRequest();
xhr.open('GET', 'https://api.jsonbin.io/b/5d5076e01ec3937ed4d05eab/1');
// set response format
xhr.responseType = 'json';
xhr.send();
xhr.onload = () => {
// get JSON response
const user = xhr.response;
// log details
console.log(user.name); // John Doe
console.log(user.email); // john.doe@example.com
console.log(user.website); // http://example.com
}
请求状态(xhr.readyState
)
对象XMLHttpRequest
的状态会随着请求的进行而改变。我们可以使用xhr.readyState
属性访问当前状态。
这些州是:
UNSENT
(0)——初始状态OPENED
(1)— 请求开始HEADERS_RECEIVED
(2) — 收到的 HTTP 标头LOADING
(3)— 响应正在加载DONE
(4)— 请求已完成
我们可以使用事件来跟踪请求状态onreadystatechange
:
xhr.onreadystatechange = function () {
if(xhr.readyState == 1) {
console.log('Request started.');
}
if(xhr.readyState == 2) {
console.log('Headers received.');
}
if (xhr.readyState == 3) {
console.log('Data loading..!');
}
if (xhr.readyState == 4) {
console.log('Request ended.');
}
};
中止请求
abort()
我们可以随时通过调用对象上的方法轻松中止 XHR 请求xhr
:
xhr.abort(); // cancel request
同步请求
默认情况下,XHR 会发出异步请求,这有利于提高性能。但是,如果您想显式地发出同步请求,只需将false
第三个参数传递给open()
方法即可。它会暂停 JavaScript 执行,send()
并在响应可用时恢复执行:
xhr.open('GET', 'https://api.jsonbin.io/b/5d5076e01ec3937ed4d05eab/1', false);
注意! Chrome 会对同步 XHR 请求显示以下警告:[弃用] 主线程上的同步 XMLHttpRequest 已被弃用,因为它会对最终用户的体验产生不利影响。
HTTP 标头
XMLHttpRequest
允许我们设置请求头以及读取响应头。我们可以通过调用对象上的方法来设置请求头Content-Type
和响应头:Accept
setRequestHeader()
xhr
// set request headers
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Accept', '*/*'); // accept all
类似地,如果您想读取响应头(除Set-Cookie
),请getResponseHeader()
调用xhr
对象:
// read response headers
xhr.getResponseHeader('Content-Type');
xhr.getResponseHeader('Cache-Control');
想要立即获取响应头?请使用getAllResponseHeaders()
:
xhr.getAllResponseHeaders();
XHR POST 请求
XMLHttpRequest
提交表单数据的 POST 请求可以通过两种方式发送:
- 仅使用 Ajax
- 使用
FormData
API
第一种方法已经足够好了,除非您要上传文件并需要multipart/form-data
编码。以下是如何使用 URL 编码的表单数据发出 POST 请求:
const xhr = new XMLHttpRequest();
// configure a `POST` request
xhr.open('POST', '/login');
// prepare form data
let params = 'username=attacomsian&password=123456';
// set `Content-Type` header
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// pass `params` to `send()` method
xhr.send(params);
// listen for `load` event
xhr.onload = () => {
console.log(xhr.responseText);
}
想要发起 JSON POST 请求吗?请确保使用JSON.stringify()将 JSON 数据转换为字符串,并将Content-Type
标头设置为application/json
:
const xhr = new XMLHttpRequest();
// configure a `POST` request
xhr.open('POST', '/login');
// create a JSON object
const json = {
username: 'attacomsian',
password: '123456'
};
// set `Content-Type` header
xhr.setRequestHeader('Content-Type', 'application/json');
// pass `params` to `send()` method
xhr.send(JSON.stringify(params));
// listen for `load` event
xhr.onload = () => {
console.log(xhr.responseText);
}
跨域请求和 Cookie
XMLHttpRequest
可以发送跨域请求,但需要遵守特殊的安全措施。要从其他服务器请求资源,服务器必须使用 CORS(跨域资源共享)明确支持此功能。
与Fetch API类似,XHR 不会向其他来源发送 Cookie 和 HTTP 授权。要发送 Cookie,可以使用对象withCredentials
的属性xhr
:
xhr.withCredentials = true;
XHR 与 jQuery
jQuery 包装器方法$.ajax()
在底层使用了 XHR,并提供了更高级别的抽象,以简化开发人员的工作。使用 jQuery,我们可以将上面的代码简化为几行:
$.ajax('https://jsonplaceholder.typicode.com/users')
.done(data => {
console.log(data);
}).fail(err => {
console.error('Error:', err);
});
XHR 与 Fetch API 对比
Fetch API是基于 Promise 的XHR 现代替代方案。它简洁、易懂,并且在PWA Service Workers中被广泛使用。
上面的 XHR 示例可以转换为更简单的fetch()
基于 的代码,甚至可以自动解析返回的 JSON:
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(json => console.log(json))
.catch(err => console.error('Error:', err));
✌️ 我撰写有关现代 JavaScript、Node.js、Spring Boot以及所有Web 开发方面的文章。订阅我的新闻通讯,每周获取 Web 开发教程和专业技巧。
喜欢这篇文章吗? 请在 Twitter 上关注 @attacomsian。你也可以在LinkedIn和DEV上关注我。
鏂囩珷鏉ユ簮锛�https://dev.to/attacomsian/introduction-to-xmlhttprequest-xhr-142j