Axios介绍

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 端另有配置点。