一、Axios 的核心原理
从本质上讲,Axios 是一个基于 Promise 的 HTTP 客户端,用于浏览器和 Node.js 环境。这句话包含了它的几个核心要点,我们来逐一拆解。
浏览器端:axios是利用的promise+ xhr请求.
1. 基于 Promise 的 API
这是 Axios 最基础也是最重要的特性。在早期,网络请求(例如使用 XMLHttpRequest)是基于回调函数的。这很容易导致“回调地狱”(Callback Hell),代码难以阅读和维护。
codeJavaScript
// 回调地狱的伪代码
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
// 使用 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
// 添加请求拦截器
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)的防护机制。
- 更丰富的配置: 提供了全局配置、实例配置和单次请求配置,非常灵活。
axios的各种用法
🧩 函数分析
export const uploadImage = (
file: File,
options?: {
onProgress?: (percent: number) => void;
category?: string;
folder?: string;
}
): Promise<Result<ImageItem>> => {
return upload<ImageItem>({
url: '/upload',
file,
onProgress: options?.onProgress,
data: {
...(options?.category && { category: options.category }),
...(options?.folder && { folder: options.folder }),
},
});
};
-
第一个参数
file:就是你要上传的文件对象,一般是从<input type="file">里获取的。 -
第二个参数
options:是一个可选配置对象,包括:onProgress: 上传进度回调函数(会不断被调用)。category: 上传分类。folder: 上传文件夹路径。
返回值是一个 Promise<Result<ImageItem>>,所以你可以用 await 或 .then() 来接收结果。
✅ 调用示例
示例 1:最简单的调用
const file = input.files?.[0]; // 从 <input type="file"> 中获取
if (file) {
const res = await uploadImage(file);
console.log(res);
}
示例 2:带进度条的调用
const file = input.files?.[0];
if (file) {
const res = await uploadImage(file, {
onProgress: (percent) => {
console.log("上传进度:", percent + "%");
},
});
console.log("上传完成:", res);
}
示例 3:带分类和文件夹路径
const file = input.files?.[0];
await uploadImage(file, {
category: "avatar",
folder: "users/profile",
onProgress: (percent) => {
console.log(`上传进度:${percent}%`);
},
});
示例 4:结合组件使用(React 举例)
function UploadAvatar() {
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const res = await uploadImage(file, {
category: "avatar",
onProgress: (percent) => {
console.log("上传中:", percent, "%");
},
});
console.log("上传结果:", res);
};
return <input type="file" onChange={handleChange} />;
}
💡总结:
| 调用方式 | 说明 |
|---|---|
uploadImage(file) | 最简调用 |
uploadImage(file, { onProgress }) | 带进度监听 |
uploadImage(file, { category, folder }) | 指定分类和目录 |
await / .then() | 都可以接收返回结果 |
是否希望我也帮你补上 upload<T>() 的实现参考?那样你能完整地看到 uploadImage() 背后是怎么工作的。
你说:
讲讲axios的各种用法?
ChatGPT 说:
好!Axios 是前端最常用的 HTTP 请求库之一。
下面我会系统地讲解 Axios 的各种用法,包括:
🌱 基础使用 → 🌾 参数配置 → ⚙️ 拦截器 → 📦 并发请求 → 🧩 文件上传下载 → 🧠 封装与进阶技巧
🌱 一、基础用法
Axios 默认支持 Promise,所以最简单的方式如下:
import axios from "axios";
// GET 请求
axios.get("/api/user").then((res) => {
console.log(res.data);
});
// POST 请求
axios.post("/api/login", { username: "admin", password: "123456" });
等价的 await 写法:
const res = await axios.get("/api/user");
console.log(res.data);
🌾 二、常用请求方式
axios.get("/api/list"); // GET
axios.post("/api/add", { name: "Tom" }); // POST
axios.put("/api/update/1", { name: "Tom" }); // PUT
axios.delete("/api/delete/1"); // DELETE
axios.patch("/api/update-part/1", { age: 18 }); // PATCH
⚙️ 三、配置参数(config)
Axios 所有方法都可以带一个配置对象。
axios({
method: "post",
url: "/api/upload",
data: { name: "Alice" },
headers: {
"Content-Type": "application/json",
Authorization: "Bearer token",
},
timeout: 5000,
params: { page: 1, size: 10 },
});
常用配置项:
| 配置项 | 说明 |
|---|---|
url | 请求地址 |
method | 请求方式 |
baseURL | 基础路径 |
headers | 请求头 |
params | URL 查询参数(GET) |
data | 请求体数据(POST、PUT) |
timeout | 超时时间(ms) |
responseType | 响应类型(json / blob / arraybuffer) |
onUploadProgress | 上传进度回调 |
onDownloadProgress | 下载进度回调 |
🧰 四、创建实例(推荐用法)
一般我们会创建一个带基础配置的实例,这样更灵活:
const api = axios.create({
baseURL: "https://api.example.com",
timeout: 8000,
headers: { "Content-Type": "application/json" },
});
// 使用实例
api.get("/user");
api.post("/login", { username: "xx" });
🧩 五、请求与响应拦截器
拦截器可以在请求发出前、响应到达后做统一处理:
api.interceptors.request.use(
(config) => {
// 比如自动带上 token
const token = localStorage.getItem("token");
if (token) config.headers.Authorization = `Bearer ${token}`;
return config;
},
(error) => Promise.reject(error)
);
api.interceptors.response.use(
(response) => {
// 统一处理成功响应
return response.data;
},
(error) => {
// 统一处理错误
console.error("请求错误:", error);
return Promise.reject(error);
}
);
📦 六、并发请求
同时发多个请求,用 axios.all:
axios
.all([axios.get("/user"), axios.get("/orders")])
.then(axios.spread((user, orders) => {
console.log(user.data, orders.data);
}));
或更现代的写法:
const [user, orders] = await Promise.all([
axios.get("/user"),
axios.get("/orders"),
]);
📤 七、上传文件
const formData = new FormData();
formData.append("file", file);
formData.append("category", "avatar");
axios.post("/upload", formData, {
headers: { "Content-Type": "multipart/form-data" },
onUploadProgress: (e) => {
const percent = Math.round((e.loaded * 100) / e.total);
console.log("上传进度:", percent + "%");
},
});
📥 八、下载文件
const res = await axios.get("/file/download", { responseType: "blob" });
const blob = new Blob([res.data]);
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "example.pdf";
a.click();
URL.revokeObjectURL(url);
🧠 九、请求封装(实际项目中常见)
一般会封装成一个统一的请求方法:
const request = axios.create({
baseURL: "/api",
timeout: 10000,
});
request.interceptors.response.use(
(res) => res.data,
(err) => {
console.error("接口错误:", err);
return Promise.reject(err);
}
);
// 使用封装
export const getUser = (id: number) => request.get(`/user/${id}`);
export const addUser = (data: any) => request.post("/user", data);
🔥 十、进阶技巧
✅ 取消请求
const controller = new AbortController();
axios.get("/api/data", { signal: controller.signal });
// 取消请求
controller.abort();
✅ 设置默认配置
axios.defaults.baseURL = "https://api.xxx.com";
axios.defaults.headers.common["Authorization"] = "Bearer token";
实战例子
axios 请求拦截器 config 的配置
// 添加时间戳防止缓存
if (config.method === 'get') {
config.params = {
...config.params,
_t: Date.now(),
};
}
Axios 请求拦截器 config 中包含哪些参数?
🔥 最常用的参数(你写拦截器时基本只用这些)
| 参数 | 类型 | 作用 |
|---|---|---|
url | string | 请求地址 |
method | string | 请求方法(get/post/put/delete…) |
baseURL | string | 基础地址 |
headers | AxiosHeaders | 请求头对象 |
params | any | GET 查询参数(会自动拼到 URL 上) |
data | any | POST/PUT/PATCH 的 body 数据 |
timeout | number | 请求超时(毫秒) |
withCredentials | boolean | 是否携带 cookie |
signal | AbortSignal | 用于取消请求 |
transformRequest | Function | 发送前对 data 做处理 |
onUploadProgress | Function | 上传进度回调 |
onDownloadProgress | Function | 下载进度回调 |
axios 响应拦截器 response 的值
interface AxiosResponse<T = any> {
data: T; // 服务器返回的数据
status: number; // HTTP 状态码 (200/400/500...)
statusText: string; // 状态文本 (OK / Not Found) 一般不用
headers: AxiosResponseHeaders; // 响应头
config: InternalAxiosRequestConfig; // 当时的请求配置
request?: any; // 原生的请求对象(XMLHttpRequest)
}
axios 响应拦截器 错误的回调函数 error的属性有哪些?
🧩 总结(你最常用的其实只有这 4 个)
| 字段 | 意义 |
|---|---|
error.response | 服务器返回的错误响应(如 400、500) |
error.request | 请求发出但没响应(断网等) |
error.code | 错误类型(超时、网络错误等) |
error.config | 原请求配置(可用于重试) |
🔥 1. error.response(最重要)
当服务器返回 4xx/5xx 时会有 response。
结构和正常 response 一样:
error.response.data
error.response.status
error.response.headers
error.response.config
🔥 2. error.config(请求配置)
无论成功失败,这个一定有。
error.config.url
error.config.method
error.config.headers
经常用于 重新发请求(如 refresh token 重试):
const originalRequest = error.config;
🔥 3. error.code(错误类型字符串)
常见值:
| error.code | 意义 |
|---|---|
ECONNABORTED | 超时 |
ERR_NETWORK | 网络错误(断网) |
ERR_BAD_REQUEST | 4xx 之类 |
ERR_BAD_RESPONSE | 5xx 之类 |
ERR_CANCELED | 请求被取消(AbortController) |
🔥 4. error.request(底层 XHR 对象)
浏览器中的原生 XMLHttpRequest
通常不用。
但可以用来判断是否完全没收到服务器响应:
if (error.request && !error.response) {
console.log("请求已发出,但服务器无响应");
}