一、Axios 的核心原理
从本质上讲,Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。这句话包含了它的几个核心要点,我们来逐一拆解。
1. 基于 Promise 的 API
这是 Axios 最基础也是最重要的特性。在早期,网络请求(例如使用 XMLHttpRequest)是基于回调函数的。这很容易导致"回调地狱"(Callback Hell),代码难以阅读和维护。
codeJavaScript
javascript
// 回调地狱的伪代码
ajax('api/user', function(user) {
ajax('api/posts?userId=' + user.id, function(posts) {
ajax('api/comments?postId=' + posts[0].id, function(comments) {
console.log(comments);
}, handleError);
}, handleError);
}, handleError);
Axios 将这些异步操作封装成了 Promise。Promise 是一种更优雅地处理异步操作的模式,它允许我们使用 .then(), .catch(), .finally() 以及 async/await 语法来编写更线性和可读的代码。
codeJavaScript
vbnet
// 使用 Axios (async/await)
async function fetchComments() {
try {
const userResponse = await axios.get('api/user');
const postsResponse = await axios.get('api/posts?userId=' + userResponse.data.id);
const commentsResponse = await axios.get('api/comments?postId=' + postsResponse.data[0].id);
console.log(commentsResponse.data);
} catch (error) {
handleError(error);
}
}
原理 : Axios 内部创建并返回一个 Promise 对象。当请求成功时,它会调用 Promise 的 resolve 函数,并将响应数据传递出去;当请求失败时,它会调用 reject 函数,并传递一个错误对象。
2. 同构性(Isomorphic):浏览器与 Node.js 通用
这是一个非常强大的特性。 "同构"意味着同一套代码可以在不同的环境(客户端和服务器端)中运行。 Axios 是如何做到的呢?
- 在浏览器端:它底层封装的是 XMLHttpRequest (XHR) 对象。这是浏览器提供的原生 API,用于发送 HTTP 请求。
- 在 Node.js 端:它底层封装的是 Node.js 内置的 http 或 https 模块。因为 Node.js 环境中没有 XHR 这个浏览器 API。
Axios 通过一个**适配器(Adapter)**层来判断当前运行环境,并选择合适的底层 API 来发送请求。这使得开发者无需关心底层实现细节,用一套统一的 axios() API 即可完成在任何环境下的网络请求。
3. 拦截器(Interceptors)
拦截器是 Axios 的一个核心且非常实用的功能。它允许你在请求发送之前 或响应返回之后对它们进行拦截和处理。
-
请求拦截器 (Request Interceptor) :在请求被发送到服务器之前,可以用来做一些统一处理,例如:
- 为每个请求添加认证 token 到请求头(headers)中。
- 开启请求加载动画(loading aniamtion)。
- 对请求数据进行统一的格式化。
-
响应拦截器 (Response Interceptor) :在 .then() 或 .catch() 被触发之前,可以对响应数据进行预处理,例如:
- 统一处理 HTTP 错误码(如 401 未授权,直接跳转到登录页)。
- 关闭加载动画。
- 对返回的数据进行解构,只返回核心的 data 部分。
原理 : Axios 内部维护了两个拦截器数组(一个请求,一个响应)。当一个请求发出时,它会像一个链条一样执行:请求拦截器 -> 发送请求 -> 响应拦截器 -> 返回给用户的 Promise。请求拦截器是"后进先出"(LIFO)的顺序执行,而响应拦截器是"先进先出"(FIFO)的顺序执行。
codeJavaScript
ini
// 添加请求拦截器
axios.interceptors.request.use(config => {
// 在发送请求之前做些什么
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}, error => {
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(response => {
// 对响应数据做点什么,例如只返回 data
return response.data;
}, error => {
// 对响应错误做点什么
if (error.response.status === 401) {
// 跳转到登录页
}
return Promise.reject(error);
});
4. 请求和响应数据转换
Axios 会自动处理请求和响应数据的转换。
- 请求时: 如果你传递一个 JavaScript 对象作为 data,Axios 会自动将其 JSON.stringify() 并设置请求头 Content-Type 为 application/json。
- 响应时: 如果收到的响应头 Content-Type 是 application/json,Axios 会自动为你 JSON.parse() 响应体,所以你直接就能拿到 JavaScript 对象。
原理: 这是通过 transformRequest 和 transformResponse 这两个配置项实现的。它们是一组函数,允许你在请求发送前和响应返回后修改数据。
5. 其他核心功能
- 请求取消: 允许在请求未完成时取消它,以避免不必要的网络流量和资源占用。
- 超时设置: 可以设置请求超时时间,防止请求长时间无响应。
- CSRF 防护: 内置了对客户端跨站请求伪造(CSRF)的防护机制。
- 更丰富的配置: 提供了全局配置、实例配置和单次请求配置,非常灵活。