实现Axios
Axios的底层实现
Axios 的底层基于两种技术:
- 浏览器端使用 XHR (XMLHttpRequest):在浏览器环境下,Axios 使用 XMLHttpRequest 来发送 HTTP 请求。它对 XMLHttpRequest 进行了封装,使得接口更为现代化和易于使用。 Axios 实现基于 Promise 和 XHR (XMLHttpRequest) 的请求,主要通过对 XHR 进行封装,并结合 JavaScript 的 Promise 机制来管理异步操作。
- Node.js 环境下使用 http 模块:在 Node.js 环境下,Axios 使用 Node.js 原生的 http 和 https 模块来发送 HTTP 请求,这使得它可以在服务器端使用,且具有跨平台的能力。
这里主要讲解在浏览器端使用的axios的底层实现。
1. 创建 Axios 实例
首先,Axios 的请求通过一个配置对象初始化,类似于创建一个 Axios 实例。该配置对象包括 url
、method
、headers
等参数。
const axiosInstance = axios.create({
baseURL: 'https://api.example.com',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
2. 封装 XHR 请求
在发送请求时,Axios 封装了 XMLHttpRequest
。主要流程如下:
-
创建 XHR 对象:通过
new XMLHttpRequest()
创建一个新的 XHR 对象。 -
配置请求:通过
xhr.open(method, url, async)
配置请求的方法和目标 URL,并设置是否为异步请求(一般设置为true
)。 -
设置请求头:使用
xhr.setRequestHeader
方法来设置请求头,比如Content-Type
或者自定义的认证 token。 -
处理响应:定义
onreadystatechange
事件处理函数,监听 XHR 对象的readyState
和status
,当请求完成时(readyState === 4
),根据状态码来判断请求是否成功,并解析响应数据。 -
发送请求:通过
xhr.send(data)
发送请求,其中data
是请求的主体数据,比如 JSON 数据或表单数据。
3. 使用 Promise 封装异步逻辑
Axios 将上述 XHR 请求逻辑封装在一个 Promise 内,这样开发者可以通过链式调用 .then()
和 .catch()
来处理成功和失败的情况。
Axios 请求的核心逻辑:
-
Promise 实例化:Axios 在发起请求时,返回一个新的 Promise 实例。
-
请求成功时调用 resolve:当请求成功(HTTP 状态码在 2xx 范围内),调用
resolve(response)
,将响应数据传递给.then()
方法处理。 -
请求失败时调用 reject:当请求失败(如网络错误或 HTTP 状态码在 4xx 或 5xx 范围内),调用
reject(error)
,将错误信息传递给.catch()
方法处理。
function axiosRequest(config) {
return new Promise(function (resolve, reject) {
const xhr = new XMLHttpRequest();
xhr.open(config.method, config.url, true);
// 设置请求头
for (const header in config.headers) {
xhr.setRequestHeader(header, config.headers[header]);
}
// 检查是否有取消请求的需求
if (config.cancelToken) {
config.cancelToken.promise.then(function onCanceled(cancel) {
if (request) {
request.abort(); // 调用 XMLHttpRequest.abort() 取消请求
reject(cancel);
request = null;
}
});
}
// 处理响应
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) { // 请求完成
if (xhr.status >= 200 && xhr.status < 300) {
// 请求成功,解析响应数据
resolve({
data: JSON.parse(xhr.responseText),
status: xhr.status,
statusText: xhr.statusText,
headers: xhr.getAllResponseHeaders(),
config: config,
request: xhr
});
} else {
// 请求失败
reject({
status: xhr.status,
statusText: xhr.statusText,
config: config,
request: xhr
});
}
}
};
// 处理网络错误
xhr.onerror = function () {
reject({
status: xhr.status,
statusText: xhr.statusText,
config: config,
request: xhr
});
};
// 发送请求
xhr.send(config.data);
});
}