一、初识 Axios
1.1 什么是 Axios
| 概念名称 | 说明 | 注意事项 |
|---|
| Axios | 基于 Promise 的 HTTP 客户端,可用于浏览器和 Node.js 环境,用于发送异步 HTTP 请求。 | 不是原生 JavaScript API,需通过 npm 或 CDN 引入。 |
| HTTP 客户端 | 允许前端应用与后端服务器通过 HTTP 协议进行数据交互(如获取数据、提交表单等)。 | 主要用于与 RESTful API 或 GraphQL 接口通信。 |
| Promise | Axios 所有请求返回 Promise 对象,支持 .then()/.catch() 和 async/await 语法。 | 需理解 Promise 基本用法以正确处理异步操作。 |
1.2 Axios 的核心特性
| 特性名称 | 说明 | 注意事项 |
|---|
| 浏览器支持 | 在浏览器中发送 XMLHttpRequests 请求。 | 支持所有现代浏览器,包括 IE11(需 polyfill)。 |
| Node.js 支持 | 在服务器端发送 http 请求。 | 使用 Node.js 的内置 http 模块,无需额外依赖。 |
| 请求/响应拦截 | 提供拦截器机制,可在请求发出前或响应返回后统一处理。 | 常用于添加 Token、日志记录、错误统一处理等。 |
| 自动转换数据 | 自动将请求数据序列化为 JSON,自动解析响应数据为 JSON。 | 默认行为,可通过配置覆盖。 |
| 客户端防御 XSRF | 可配置以防止跨站请求伪造攻击。 | 需后端配合设置 cookie 和验证机制。 |
| 取消请求 | 支持使用 AbortController API 取消请求。 | 已弃用旧的 CancelToken 方式,推荐使用 AbortController。 |
| 请求进度监控 | 支持上传和下载进度事件监听。 | 仅在浏览器环境有效,Node.js 不支持。 |
1.3 浏览器与 Node.js 环境支持
| 环境类型 | 支持情况 | 注意事项 |
|---|
| 浏览器 | 完全支持,基于 XMLHttpRequest 或 fetch(适配器实现) | 需注意跨域问题(CORS),需后端配置响应头。 |
| Node.js | 完全支持,基于内置 http 模块 | 可用于服务端渲染(SSR)、脚本任务、微服务调用等场景。 |
| React Native | 支持,视为浏览器环境运行 | 可正常使用所有浏览器特性。 |
| Web Workers | 支持有限 | 不支持某些 DOM 相关功能(如 FormData),需注意兼容性。 |
| Electron | 主进程(Node)和渲染进程(浏览器)均支持 | 根据运行上下文自动选择适配器。 |
二、快速上手
2.1 安装与引入方式(npm / CDN)
| 方式 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| npm 安装 | npm install axios | 在 Node.js 或前端构建项目中安装 Axios | npm install axios | 推荐方式,便于版本管理和 tree-shaking。 |
| | | import axios from 'axios'; | |
| yarn 安装 | yarn add axios | 同上,使用 Yarn 包管理器 | yarn add axios | 功能等价于 npm 安装。 |
| | | import axios from 'axios'; | |
| CDN 引入 | 无 | 在 HTML 中通过 script 标签引入 | <script src="https://unpkg.com/axios/dist/axios.min.js"></script> | 全局暴露 axios 变量,适合简单项目或学习使用。 |
| ES6 模块导入 | import axios from 'axios' | 在支持模块化的环境中导入 | import axios from 'axios'; | 适用于 Vue、React、Webpack/Vite 项目。 |
| CommonJS 导入 | const axios = require('axios') | 在 Node.js 或不支持 ES6 模块的环境中使用 | const axios = require('axios'); | 传统 Node.js 项目常用方式。 |
2.2 创建第一个 axios 实例
| 类别 | 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建实例 | axios.create([config]) | axios.create({ ...配置项 }) | 创建一个独立的 axios 实例,拥有自定义配置(如 baseURL、headers 等),用于特定用途(如不同 API 服务)。 | const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 5000,
headers: { 'Content-Type': 'application/json' }
});
api.get('/users'); // 使用该实例 | - 实例之间配置互不影响。 - 适合多 API 源、环境隔离。 - 可创建多个实例用于不同服务。 |
| 全局默认配置 | axios.defaults | axios.defaults.属性 = 值 | 设置所有 axios 请求的默认行为(如默认 baseURL、timeout、headers)。 | axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 3000;
axios.defaults.headers.common['Authorization'] = 'Bearer token';
axios.get('/users'); // 自动使用默认配置 | - 影响所有 axios 请求(包括 axios.get、axios.post 等)。 - 不推荐在库中使用,可能影响调用方。 - 可被实例配置覆盖。 |
2.3 发送第一个 GET 请求
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.get | axios.get(url[, config]) | 向指定 URL 发送 GET 请求获取数据 | axios.get('/user', {
params: { id: 123 }
})
.then(response => {
console.log(response.data);
}); | params 用于拼接查询字符串,如 ?id=123。 |
axios | axios(config) | 通用请求方法,配置 method 为 'get' | axios({
method: 'get',
url: '/user',
params: { id: 123 }
})
.then(response => {
console.log(response.data);
}); | 更灵活,适合复杂配置场景。 |
2.4 发送第一个 POST 请求
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.post | axios.post(url, data[, config]) | 向指定 URL 发送 POST 请求提交数据 | axios.post('/user', {
name: 'John',
age: 30
})
.then(response => {
console.log(response.data);
}); | 第二个参数为请求体数据,自动序列化为 JSON。 |
axios | axios(config) | 通用请求方法,配置 method 为 'post' | axios({
method: 'post',
url: '/user',
data: { name: 'John', age: 30 }
})
.then(response => {
console.log(response.data);
}); | 适用于需要精细控制请求头、超时等配置的场景。 |
2.5 基本请求方法别名使用
| 方法别名 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.get | axios.get(url[, config]) | 发送 GET 请求 | axios.get('/api/users')
.then(res => console.log(res.data)); | 用于读取资源。 |
axios.delete | axios.delete(url[, config]) | 发送 DELETE 请求 | axios.delete('/api/users/1')
.then(res => console.log(res.data)); | 用于删除资源,可携带 params。 |
axios.head | axios.head(url[, config]) | 发送 HEAD 请求 | axios.head('/api/users/1')
.then(res => console.log(res.headers)); | 获取响应头信息,不返回响应体。 |
axios.options | axios.options(url[, config]) | 发送 OPTIONS 请求 | axios.options('/api/users')
.then(res => console.log(res.headers)); | 用于预检请求(CORS)或获取接口支持的方法。 |
axios.post | axios.post(url, data[, config]) | 发送 POST 请求 | axios.post('/api/users', { name: 'Tom' })
.then(res => console.log(res.data)); | 用于创建资源。 |
axios.put | axios.put(url, data[, config]) | 发送 PUT 请求 | axios.put('/api/users/1', { name: 'Tom' })
.then(res => console.log(res.data)); | 用于完整更新资源。 |
axios.patch | axios.patch(url, data[, config]) | 发送 PATCH 请求 | axios.patch('/api/users/1', { name: 'Tom' })
.then(res => console.log(res.data)); | 用于部分更新资源。 |
注意:所有别名方法均返回 Promise,可链式调用 .then/.catch 或使用 async/await。
三、Axios 请求配置详解
请求配置优先级:请求配置 > 实例配置 > 全局配置
3.1 全局配置(axios.defaults)
| 配置项 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.defaults.baseURL | axios.defaults.baseURL = 'url' | 设置所有请求的默认基础 URL | axios.defaults.baseURL = 'https://api.example.com';
axios.get('/users'); // 实际请求: https://api.example.com/users | 影响所有后续请求,包括实例和别名方法。 |
axios.defaults.timeout | axios.defaults.timeout = 毫秒数 | 设置请求超时时间 | axios.defaults.timeout = 5000; // 5秒超时 | 超时后 Promise 被 reject,需错误处理。 |
axios.defaults.headers | axios.defaults.headers['Header-Name'] = 'value' | 设置默认请求头 | axios.defaults.headers['Authorization'] = 'Bearer token';
axios.defaults.headers.post['Content-Type'] = 'application/json'; | 可按方法(get/post/put 等)设置特定头。 |
axios.defaults.transformRequest | axios.defaults.transformRequest = [function] | 自定义请求数据序列化 | axios.defaults.transformRequest = [function(data) {
return JSON.stringify(data);
}]; | 通常用于修改 POST/PUT 数据格式。 |
axios.defaults.transformResponse | axios.defaults.transformResponse = [function] | 自定义响应数据解析 | axios.defaults.transformResponse = [function(data) {
return JSON.parse(data);
}]; | 可用于预处理响应体(如加解密)。 |
3.2 自定义实例配置(axios.create)
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.create | axios.create(config) | 创建一个具有自定义配置的 axios 实例 | const instance = axios.create({
baseURL: 'https://api.example.com/v1',
timeout: 3000,
headers: { 'X-Custom-Header': 'foobar' }
});
instance.get('/users'); | 实例独立于全局配置,适合多接口域名项目。 |
| 实例方法调用 | instance.request(config) | 使用实例发送请求 | instance.post('/login', {
username: 'admin'
}); | 支持 .get、.post、.put 等所有别名方法。 |
| 多实例管理 | 多个 create 调用 | 管理不同服务的请求配置 | const userApi = axios.create({ baseURL: '/users' });
const orderApi = axios.create({ baseURL: '/orders' }); | 避免配置冲突,提升代码可维护性。 |
3.3 请求配置项(config)完整参数说明
| 配置项 | 类型 | 用途 | 代码示例 | 注意事项 |
|---|
url | string | 请求地址(必填) | { url: '/user' } | 若使用实例,会与 baseURL 拼接。 |
method | string | 请求方法 | { method: 'post' } | 默认为 GET。 |
baseURL | string | 基础 URL | { baseURL: 'https://api.example.com' } | 优先级高于全局 defaults。 |
headers | object | 自定义请求头 | { headers: { 'Authorization': 'Bearer x' } } | 可覆盖默认 headers。 |
params | object | URL 查询参数 | { params: { id: 123 } } → ?id=123 | 仅用于 GET、HEAD 等方法。 |
data | any | 请求体数据(POST/PUT/PATCH) | { data: { name: 'John' } } | 自动序列化为 JSON(默认)。 |
timeout | number | 超时时间(毫秒) | { timeout: 5000 } | 超时后请求中断,Promise reject。 |
withCredentials | boolean | 是否携带跨域凭证(Cookie) | { withCredentials: true } | 需后端设置 Access-Control-Allow-Credentials。 |
responseType | string | 响应数据类型 | { responseType: 'blob' } | 可选:'json'、'text'、'document'、'stream'、'arraybuffer'。下载文件时常用 blob 或 arraybuffer。 |
onUploadProgress | function | 上传进度回调 | { onUploadProgress: (progressEvent) => {
const percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log(percent);
} } | 仅浏览器环境有效。 |
onDownloadProgress | function | 下载进度回调 | { onDownloadProgress: (progressEvent) => {
console.log(progressEvent.loaded);
} } | 仅浏览器环境有效。 |
transformRequest | function | array | 请求数据预处理 | { transformRequest: [(data) => JSON.stringify(data)] } | 可用于加密或格式转换。 |
transformResponse | function | array | 响应数据后处理 | { transformResponse: [(data) => JSON.parse(data)] } | 可用于统一数据结构处理。 |
validateStatus | function | 自定义状态码成功判断 | { validateStatus: (status) => status < 400 } | 默认只将 2xx 视为成功。 |
四、处理响应与错误
4.1 响应结构解析
| 属性名 | 类型 | 说明 | 代码示例 | 注意事项 |
|---|
data | any | 服务器返回的数据(已解析) | axios.get('/user').then(res => {
console.log(res.data); // 如: { id: 1, name: 'John' }
}); | 默认自动 JSON 解析,无需手动 JSON.parse。 |
status | number | HTTP 状态码 | res.status // 例如: 200, 404, 500 | 用于判断请求结果类型。 |
statusText | string | 状态码文本描述 | res.statusText // 例如: 'OK', 'Not Found' | 一般用于调试或日志记录。 |
headers | object | 响应头信息 | res.headers['content-type'] // 获取 content-type | 所有键名小写。 |
config | object | 请求时使用的配置 | res.config.url // 查看原始请求 URL | 便于调试和重试请求。 |
request | XMLHttpRequest | ClientRequest | 生成此响应的原始请求对象 | res.request // 浏览器中为 XMLHttpRequest 实例 | 高级用法,如调试网络问题。 |
4.2 错误类型与错误对象结构
| 错误类型 | 触发条件 | error 对象关键属性 | 示例说明 | 注意事项 |
|---|
| 请求配置错误 | 配置项不合法(如 timeout 为负数) | error.message、error.code | Error: timeout value must be a non-negative integer | 通常在请求发起前抛出。 |
| 网络错误 | 无网络、DNS 失败、连接中断 | error.message、error.request | Network Error
error.request 存在,但 error.response 为 undefined | error.response 不存在。 |
| 超时错误 | 请求超时 | error.message、error.code = 'ECONNABORTED' | timeout of 1000ms exceeded | 可通过 error.code 判断是否为超时。 |
| 服务器错误 | 服务器返回 4xx/5xx 状态码 | error.response、error.response.status | error.response.status = 404
error.response.data = { error: 'Not Found' } | error.response 存在,可获取详细信息。 |
| 取消请求 | 用户主动取消请求 | error.message、error.name = 'CanceledError' | Cancel
error.name === 'CanceledError' | 需使用 AbortController 触发。 |
4.3 使用 try-catch 处理错误
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
async/await + try-catch | try { await axios() } catch (error) {} | 在异步函数中同步方式处理错误 | async function fetchUser() {
try {
const res = await axios.get('/user/1');
console.log(res.data);
} catch (error) {
if (error.response) {
console.error('服务器错误:', error.response.status);
} else if (error.request) {
console.error('网络错误');
} else {
console.error('配置错误:', error.message);
}
}
} | 推荐现代项目使用,代码更清晰。 |
| 错误类型判断 | if (error.response) / else if (error.request) | 区分不同错误类型 | if (error.response) { /* 服务器返回了错误 */ }
else if (error.request) { /* 请求发出但无响应 */ }
else { /* 其他错误(如配置错误) */ } | 必须按此顺序判断,避免误判。 |
4.4 使用 .catch() 处理错误
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
.catch() 链式调用 | axios().catch(error => {}) | Promise 风格错误处理 | axios.get('/user/1')
.then(res => console.log(res.data))
.catch(error => {
if (error.response) {
console.error('状态码:', error.response.status);
} else {
console.error('请求失败:', error.message);
}
}); | 传统方式,适用于不支持 async/await 的环境。 |
| 全局错误捕获 | axios().catch(globalErrorHandler) | 封装统一错误处理函数 | function handleError(error) {
if (error.response?.status === 401) {
alert('登录已过期');
}
}
axios.get('/data').catch(handleError); | 提升代码复用性,避免重复逻辑。 |
finally 清理资源 | .finally(() => {}) | 无论成功失败都执行 | axios.get('/data')
.then(res => { /* 处理数据 */ })
.catch(err => { /* 处理错误 */ })
.finally(() => {
loading = false;
}); | 适合关闭加载动画、释放资源等操作。 |
五、拦截器的使用
5.1 请求拦截器(Interceptors.request)
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.interceptors.request.use | axios.interceptors.request.use(onFulfilled, onRejected) | 在请求发送前统一处理配置 | axios.interceptors.request.use(
config => {
config.headers.Authorization = 'Bearer ' + getToken();
config.startTime = Date.now();
return config;
},
error => {
return Promise.reject(error);
}
); | 必须返回 config,否则请求将被阻断。 |
| 添加请求日志 | 同上 | 记录请求信息用于调试 | config.headers['X-Request-Start'] = Date.now();
console.log('请求发出:', config.url); | 可用于性能监控。 |
| 统一设置 Token | 同上 | 自动附加认证信息 | if (config.url !== '/login') {
config.headers.Authorization = 'Bearer ' + localStorage.getItem('token');
} | 避免在每个请求中重复写。 |
5.2 响应拦截器(Interceptors.response)
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.interceptors.response.use | axios.interceptors.response.use(onFulfilled, onRejected) | 在响应返回后统一处理结果或错误 | axios.interceptors.response.use(
response => {
const duration = Date.now() - response.config.startTime;
console.log(请求耗时: ${duration}ms);
return response;
},
error => {
if (error.response?.status === 401) {
window.location.href = '/login';
}
return Promise.reject(error);
}
); | 成功回调接收响应对象,失败回调接收错误对象。 |
| 统一错误处理 | onRejected 回调 | 集中处理 401、403、500 等状态码 | if (error.response?.status === 401) {
clearAuth();
router.push('/login');
} else if (error.response?.status === 500) {
alert('服务器内部错误');
} | 避免在每个 .catch 中重复判断。 |
| 响应数据预处理 | onFulfilled 回调 | 统一提取 data 字段或转换格式 | return {
data: response.data.result,
code: response.data.code
}; | 可标准化不同接口返回结构。 |
5.3 移除拦截器与添加多个拦截器
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 添加多个拦截器 | 多次调用 use | 按顺序执行多个处理逻辑 | axios.interceptors.request.use(config => {
config.headers.A = '1';
return config;
});
axios.interceptors.request.use(config => {
config.headers.B = '2';
return config;
}); | 执行顺序为注册顺序(先进先出)。 |
| 移除拦截器 | const myInterceptor = axios.interceptors.xxx.use(...);
axios.interceptors.xxx.eject(myInterceptor); | 动态取消某个拦截器 | const reqInterceptor = axios.interceptors.request.use(config => {
config.custom = true;
return config;
});
axios.interceptors.request.eject(reqInterceptor); | eject 后该拦截器不再生效。 |
| 拦截器存储与复用 | 变量保存引用 | 在组件销毁时移除(如 Vue/React) | // Vue 中
created() {
this.interceptor = axios.interceptors.response.use(...);
}
beforeUnmount() {
axios.interceptors.response.eject(this.interceptor);
} | 防止内存泄漏或重复注册。 |
六、高级用法
6.1 并发请求:axios.all 与 axios.spread
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
axios.all | axios.all([promise1, promise2]) | 并发执行多个请求,全部成功才 resolve | axios.all([
axios.get('/users'),
axios.get('/posts')
]).then(responses => {
const users = responses[0].data;
const posts = responses[1].data;
}); | 类似 Promise.all,任一失败则整体 reject。 |
axios.spread | axios.spread(callback) | 将数组参数展开为多个参数传入回调 | axios.all([
axios.get('/users'),
axios.get('/posts')
]).then(
axios.spread((userRes, postRes) => {
console.log(userRes.data, postRes.data);
})
); | 需配合 axios.all 使用,提升可读性。 |
| 替代方案(推荐) | Promise.all | 原生方式实现并发 | try {
const [userRes, postRes] = await Promise.all([
axios.get('/users'),
axios.get('/posts')
]);
} catch (error) { /* 处理错误 */ } | axios.all 已不推荐,建议使用 Promise.all。 |
6.2 取消请求(CancelToken 已废弃 / AbortController)
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
AbortController(推荐) | new AbortController() | 标准化取消请求方式 | const controller = new AbortController();
axios.get('/data', {
signal: controller.signal
})
.catch(err => {
if (axios.isCancel(err)) {
console.log('请求被取消:', err.message);
}
});
// 取消请求
controller.abort(); | signal 是 AbortController 的核心属性。 |
| 取消时传递消息 | controller.abort('原因') | 自定义取消原因 | controller.abort('用户跳转页面');
if (axios.isCancel(err)) {
console.log(err.message); // 输出: "用户跳转页面"
} | 错误对象 err.message 即为传入的消息。 |
axios.isCancel | axios.isCancel(error) | 判断错误是否为取消操作引起 | if (axios.isCancel(error)) {
console.log('请求已取消');
} | 必须使用此方法判断,不能直接比较。 |
CancelToken(已废弃) | axios.CancelToken.source() | 旧版取消机制(不推荐) | const source = axios.CancelToken.source();
axios.get('/data', { cancelToken: source.token });
source.cancel('取消'); | 新项目请使用 AbortController。 |
6.3 上传文件与下载进度监控
| 方法/配置 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
onUploadProgress | config.onUploadProgress | 监听文件上传进度 | axios.post('/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
onUploadProgress: progressEvent => {
const percent = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
console.log(${percent}% 上传完成);
}
}); | 仅浏览器环境有效,Node.js 不支持。 |
onDownloadProgress | config.onDownloadProgress | 监听文件下载进度 | axios.get('/large-file.pdf', {
responseType: 'blob',
onDownloadProgress: progressEvent => {
console.log(已下载: ${progressEvent.loaded} 字节);
}
}); | 适用于大文件下载场景。 |
FormData 上传 | new FormData() | 构造表单数据上传文件 | const formData = new FormData();
formData.append('file', fileInput.files[0]);
axios.post('/upload', formData); | 必须设置 Content-Type 为 multipart/form-data(axios 会自动设置)。 |
6.4 自定义适配器与 mock 数据
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 自定义适配器 | adapter: function (config) {} | 替换默认的 HTTP 请求逻辑 | const mockAdapter = config => {
return new Promise(resolve => {
setTimeout(() => {
resolve({
data: { id: 1, name: 'Mock User' },
status: 200,
statusText: 'OK',
headers: {},
config
});
}, 500);
});
};
axios.get('/user', { adapter: mockAdapter }); | 用于测试、离线模式或集成非标准网络库。 |
| 全局替换适配器 | axios.defaults.adapter | 设置默认适配器 | axios.defaults.adapter = mockAdapter; | 影响所有后续请求,慎用。 |
使用 axios-mock-adapter | 第三方库 | 更强大的 mock 方案 | import MockAdapter from 'axios-mock-adapter';
const mock = new MockAdapter(axios);
mock.onGet('/users').reply(200, [{ id: 1, name: 'John' }]); | 推荐用于单元测试或开发环境 mock。 |
| 适配小程序请求 | adapter 调用 wx.request | 在微信小程序中使用 axios | adapter: config => {
return new Promise((resolve, reject) => {
wx.request({
url: config.url,
method: config.method,
data: config.data,
success: resolve,
fail: reject
});
});
} | 需自行封装兼容性逻辑。 |
七、实际项目中的最佳实践
7.1 封装统一请求模块
| 方法/配置 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 创建 axios 实例 | axios.create(config) | 隔离配置,避免污染全局 | const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL,
timeout: 10000
}); | 推荐项目中始终使用实例而非全局 axios。 |
| 封装 request 函数 | export function request(config) {} | 提供统一调用接口 | export function request(options) {
return service(options)
.then(res => res.data)
.catch(err => {
throw err;
});
} | 统一处理响应 data 层级,调用端直接获取数据。 |
| 按模块导出 API | export const userApi = { get, post } | 结构化管理接口 | export const userApi = {
getList: () => request({ url: '/users', method: 'get' }),
getById: (id) => request({ url: /users/${id}, method: 'get' })
}; | 提升可维护性,便于团队协作。 |
环境变量区分 baseURL | 使用 .env 文件 | 不同环境(dev/test/prod)请求不同地址 | # .env.development
VUE_APP_API_BASE_URL=https://dev-api.example.com
# .env.production
VUE_APP_API_BASE_URL=https://api.example.com | 避免硬编码,提升安全性。 |
7.2 状态码统一处理与提示
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 响应拦截器中判断 status | response.status | 统一处理常见状态码 | service.interceptors.response.use(
response => {
return response;
},
error => {
const { status } = error.response;
switch (status) {
case 400:
alert('请求参数错误');
break;
case 403:
alert('权限不足');
break;
case 404:
alert('请求资源不存在');
break;
case 500:
alert('服务器内部错误');
break;
default:
alert('网络异常');
}
return Promise.reject(error);
}
); | 避免在业务代码中重复写提示逻辑。 |
| 自定义业务状态码处理 | error.response.data.code | 处理后端自定义 code(如 { code: 1001, msg: '登录失效' }) | if (error.response?.data?.code === 1001) {
alert('登录已过期,请重新登录');
localStorage.removeItem('token');
location.href = '/login';
} | 前后端需约定 code 含义。 |
| 错误提示可配置化 | 引入 message/toast 组件 | 使用 UI 库提示(如 Element Plus、Ant Design) | import { Message } from 'element-plus';
Message.error('请求失败'); | 比 alert 更美观,支持自动关闭。 |
7.3 Token 认证与自动刷新
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 请求拦截器附加 Token | config.headers.Authorization | 自动携带 Token | service.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = Bearer ${token};
}
return config;
}); | 所有请求自动附加,无需手动设置。 |
| 响应拦截器处理 401 | error.response.status === 401 | 检测 Token 失效 | service.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
localStorage.removeItem('token');
location.href = '/login';
}
return Promise.reject(error);
}
); | 防止未授权请求反复尝试。 |
| Token 自动刷新机制 | refresh token | 在 Token 过期后获取新 Token | let isRefreshing = false;
let refreshSubscribers = [];
function subscribeTokenRefresh(cb) {
refreshSubscribers.push(cb);
}
service.interceptors.response.use(
response => response,
async error => {
const { status } = error.response;
if (status === 401 && !error.config._retry) {
if (!isRefreshing) {
isRefreshing = true;
const newToken = await refreshTokenAPI();
localStorage.setItem('token', newToken);
refreshSubscribers.forEach(cb => cb(newToken));
refreshSubscribers = [];
isRefreshing = false;
}
const retryConfig = error.config;
retryConfig._retry = true;
retryConfig.headers.Authorization = Bearer ${newToken};
return service(retryConfig);
}
return Promise.reject(error);
}
); | 防止多个请求同时触发刷新,需加锁(isRefreshing)和队列机制。 |
| 避免死循环 | 添加 _retry 标志 | 防止刷新后再次进入 401 逻辑 | error.config._retry = true;
return service(error.config); | 必须标记已重试,否则会无限循环。 |
7.4 超时设置与重试机制
| 方法 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|
| 全局超时设置 | timeout: 毫秒数 | 防止请求长时间挂起 | const service = axios.create({
timeout: 10000 // 10秒超时
}); | 根据业务需求合理设置,过短影响正常请求。 |
| 动态超时 | config.timeout | 按接口设置不同超时时间 | request({
url: '/large-data',
method: 'get',
timeout: 30000 // 30秒
}); | 大文件上传/下载需更长超时。 |
| 请求重试机制 | 递归 + 次数限制 | 网络波动时自动重试 | function requestWithRetry(config, retries = 3) {
return service(config).catch(async error => {
if (retries > 0 && !error.response) {
return requestWithRetry(config, retries - 1);
}
throw error;
});
} | 避免对 POST 等非幂等操作重试,防止重复提交。 |
| 指数退避重试 | setTimeout + 延迟递增 | 避免频繁重试加剧服务器压力 | const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
await delay(1000 * (4 - retries)); | 更友好的重试策略,适用于生产环境。 |
| 重试次数限制 | retries 参数控制 | 防止无限重试 | if (retries > 0) { /* 重试 */ } else { throw error; } | 建议 2~3 次为宜。 |