Axios介绍
-
早期与主流浏览器环境中,Axios主要是对 XMLHttpRequest(XHR)的封装。
-
在非浏览器环境(如 Node.js),Axios使用自有的适配器,底层基于 Node 的 http/https 模块实现。
-
近几年,Axios也提供了基于 fetch 的适配器选项,但默认仍非 fetch;是否走 fetch 取决于所用适配器/版本与配置。
展开说明:
-
适配器机制(adapters)
-
浏览器适配器:封装 XHR,提供 Promise 接口、拦截器、请求/响应转换、超时、取消(早期基于 CancelToken,后期支持 AbortController)、CSRF 辅助等。
-
Node 适配器:不使用 XHR/Fetch,而是用 http/https 构建请求,保持相同的 Axios API 语义。
-
自定义/实验性 fetch 适配器:某些版本或社区包可将底层改为 fetch(如 axios/axios v1.4+ 引入 fetch adapter 选项,或通过第三方适配器)。开启后由 fetch 驱动,但行为细节会尽量模拟 Axios 既有语义。
-
-
与原生 fetch 的差异点(为什么很多项目还用 Axios)
-
拦截器体系(请求/响应统一处理)
-
自动 JSON 序列化/解析与更一致的错误处理(非 2xx 会 reject)
-
内置超时参数、重试/重定向策略可扩展
-
更好的旧浏览器兼容历史(在不支持 fetch 的环境中可工作)
-
更丰富的请求取消与进度回调支持(基于 XHR 的 onUploadProgress/onDownloadProgress)
-
-
当前实践建议
-
现代浏览器/Node 18+:优先考虑原生 fetch(搭配轻量封装处理拦截/重试/JSON/错误),减少依赖与体积。
-
需要拦截器、进度回调、统一跨端行为或要兼容旧环境时:Axios 依然合适;若想对齐平台标准,可尝试其 fetch 适配器或使用基于 fetch 的库(如 ky、ofetch)。
-
一句话回答:
- Axios在浏览器里历来是“基于XHR的封装”,在Node里用http/https适配;它并非天然基于fetch,但现在可以切到fetch适配器,取决于你的配置与运行环境。
下面按“常用场景→示例代码→要点提示”的结构,快速覆盖 Axios 的主要用法。示例以浏览器与 Node 通用写法为主(Node 需先 npm i axios)。
一、基础请求
- GET
import axios from 'axios';
const res = await axios.get('https://api.example.com/users', {
params: { page: 1, pageSize: 20 }, // 自动序列化为 ?page=1&pageSize=20
headers: { 'X-Client': 'demo' },
});
console.log(res.status, res.data);
- POST JSON
const res = await axios.post('https://api.example.com/users',
{ name: 'Alice', role: 'admin' }, // 自动设置 Content-Type: application/json
{ timeout: 5000 }
);
- PUT / PATCH / DELETE
await axios.put('/users/123', { name: 'Bob' });
await axios.patch('/users/123', { role: 'editor' });
await axios.delete('/users/123');
二、全局与实例配置
- 创建实例(推荐为不同后端/微服务各建一个)
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 8000,
headers: { 'X-App': 'myapp' },
withCredentials: true, // 跨域携带 Cookie(需服务端允许)
});
- 使用实例
const res = await api.get('/users', { params: { page: 1 } });
- 设置全局默认值(影响所有实例/默认 axios)
axios.defaults.timeout = 10000;
axios.defaults.headers.common['X-Trace'] = 'on';
三、请求与响应拦截器
- 典型用途:统一加 token、日志、处理非 2xx 错误、自动刷新凭证
const api = axios.create({ baseURL: '/api' });
api.interceptors.request.use((config) => {
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
}, async (error) => {
const { response, config } = error;
if (response?.status === 401 && !config._retry) {
config._retry = true;
// 刷新 token 的示例
const newToken = await refreshToken();
localStorage.setItem('token', newToken);
config.headers.Authorization = `Bearer ${newToken}`;
return api(config); // 重试原请求
}
return Promise.reject(error);
});
四、并发请求与聚合
const [usersRes, postsRes] = await Promise.all([
axios.get('/api/users'),
axios.get('/api/posts'),
]);
console.log(usersRes.data, postsRes.data);
五、查询参数与序列化
-
基本 params 会自动序列化
-
复杂对象/数组可使用 paramsSerializer
import qs from 'qs';
await axios.get('/search', {
params: { tags: ['js', 'web'], range: { from: 1, to: 10 } },
paramsSerializer: (params) => qs.stringify(params, { arrayFormat: 'repeat' }),
});
// => /search?tags=js&tags=web&range%5Bfrom%5D=1&range%5Bto%5D=10
六、表单与文件上传
- application/x-www-form-urlencoded
import qs from 'qs';
await axios.post('/login',
qs.stringify({ username: 'a', password: 'b' }),
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
);
- multipart/form-data(文件上传,支持进度)
const form = new FormData();
form.append('file', fileInput.files[0]);
form.append('desc', 'avatar');
await axios.post('/upload', form, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: (e) => {
const percent = Math.round((e.loaded * 100) / (e.total ?? e.loaded));
console.log('upload', percent + '%');
},
});
七、下载文件与进度
const res = await axios.get('/report.pdf', {
responseType: 'blob',
onDownloadProgress: (e) => {
const percent = Math.round((e.loaded * 100) / (e.total ?? e.loaded));
console.log('download', percent + '%');
},
});
// 浏览器保存
const url = URL.createObjectURL(res.data);
const a = document.createElement('a');
a.href = url; a.download = 'report.pdf'; a.click();
URL.revokeObjectURL(url);
八、超时与取消请求
- 超时
await axios.get('/slow', { timeout: 3000 });
- 取消(AbortController,Axios v1+)
const controller = new AbortController();
const p = axios.get('/data', { signal: controller.signal });
setTimeout(() => controller.abort(), 1000);
await p.catch(err => console.log('aborted?', axios.isCancel(err)));
九、错误处理与类型判断
try {
const res = await axios.get('/api');
console.log(res.data);
} catch (err) {
if (axios.isAxiosError(err)) {
console.log('status', err.response?.status);
console.log('data', err.response?.data);
console.log('code', err.code); // 'ECONNABORTED' 等
} else {
console.error('unexpected', err);
}
}
十、拦截器中的重试与退避(简单示例)
const api = axios.create();
api.interceptors.response.use(undefined, async (error) => {
const config = error.config;
const retry = (config.__retryCount ?? 0);
const shouldRetry = (!error.response || error.response.status >= 500) && retry < 3;
if (!shouldRetry) throw error;
config.__retryCount = retry + 1;
const delay = 300 * 2 ** retry; // 指数退避
await new Promise(r => setTimeout(r, delay));
return api(config);
});
十一、与 fetch 的互操作(可选:fetch 适配器)
- 让 Axios 基于 fetch 运行(行为会略有差异)
import axios from 'axios';
import { fetchAdapter } from '@vespaiach/axios-fetch-adapter';
const api = axios.create({ adapter: fetchAdapter });
十二、TypeScript 提示与类型
import axios, { AxiosResponse } from 'axios';
type User = { id: number; name: string };
const res: AxiosResponse<User[]> = await axios.get('/users');
res.data.forEach(u => console.log(u.id));
十三、常见最佳实践
-
为每个后端定义 axios 实例,集中配置拦截与重试策略。
-
在响应拦截器中统一只返回 response.data,简化调用层。
-
上传/下载大文件使用 onUploadProgress/onDownloadProgress,并设定合理的 timeout 与最大内容长度限制(maxContentLength、maxBodyLength 在 Node 环境)。
-
对幂等请求(GET/PUT)才做自动重试;POST 等非幂等操作需配合幂等键或谨慎处理。
-
跨端项目(浏览器+Node)注意差异:Cookie、CORS、代理、HTTP/HTTPS Agent、证书校验等在 Node 端另有配置点。