项目集成axios二次封装
# 项目集成axios二次封装
在 Vue3 项目开发过程中,我们需要与后端 API 进行交互。为了提高开发效率和代码的可维护性,我们通常会对 axios
进行 二次封装,这样可以:
- 统一管理 API 配置,避免在多个组件中重复定义
baseURL
、超时时间等。 - 全局处理请求和响应,例如:
- 请求前:自动携带
token
,防止用户未授权访问。 - 请求后:自动解析数据,统一处理错误信息。
- 请求前:自动携带
- 优化用户体验,在网络异常时,及时给出反馈(如
ElMessage
提示)。
# 1. 安装 axios
如果你的项目还没有安装 axios
,可以使用以下命令安装:
pnpm install axios
1
或者:
npm install axios
# 或
yarn add axios
1
2
3
2
3
# 2. 创建 utils/request.ts
在 src/utils/
目录下创建 request.ts
文件,我们将在这里对 axios
进行封装,使其更符合项目需求。
import axios from "axios";
import { ElMessage } from "element-plus";
// 创建 axios 实例
const request = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, // 读取环境变量中的 API 地址
timeout: 5000, // 超时时间 5s
});
// 请求拦截器
request.interceptors.request.use(
(config) => {
// 在请求头中携带 `token`
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
(error) => {
// 请求错误
return Promise.reject(error);
}
);
// 响应拦截器
request.interceptors.response.use(
(response) => {
// 直接返回服务器的数据(去掉 `axios` 自动包裹的一层)
return response.data;
},
(error) => {
// 处理 HTTP 网络错误
let msg = "";
if (error.response) {
const status = error.response.status;
switch (status) {
case 401:
msg = "Token 过期,请重新登录";
break;
case 403:
msg = "无权限访问";
break;
case 404:
msg = "请求地址不存在";
break;
case 500:
msg = "服务器错误,请稍后再试";
break;
default:
msg = "网络连接失败";
}
} else {
msg = "请求超时,请检查网络";
}
// 提示错误信息
ElMessage.error(msg);
// 返回失败的 `Promise`
return Promise.reject(error);
}
);
export default request;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 3. 统一 API 配置
# 全局 baseURL
设置
在 request.ts
文件中,我们使用:
baseURL: import.meta.env.VITE_APP_BASE_API
1
它会从 环境变量 读取 API 地址,支持不同环境(开发、生产)自动切换:
# .env.development
VITE_APP_BASE_API = "http://localhost:3000/api"
# .env.production
VITE_APP_BASE_API = "https://api.example.com"
1
2
3
4
5
2
3
4
5
这样,在 开发环境 和 生产环境 下,API 地址会自动匹配,无需手动更改。
# 4. 请求拦截器:自动携带 token
request.interceptors.request.use(
(config) => {
const token = localStorage.getItem("token");
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}
);
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
拦截器作用:
- 在 每次请求前,自动读取
token
并添加到请求头,确保需要授权的接口能正常访问。 - 避免手动在每个 API 调用时都要传递
token
,减少代码重复。
# 5. 响应拦截器:自动处理 API 响应
request.interceptors.response.use(
(response) => {
return response.data; // 直接返回 data,简化数据结构
}
);
1
2
3
4
5
2
3
4
5
拦截器作用:
- 简化 API 数据格式:去掉
axios
默认的response.data
结构,调用 API 时直接拿到服务器返回的数据。 - 减少
data.data
嵌套问题,前端不再需要res.data.data
,直接使用res.data
。
# 6. 处理 HTTP 网络错误
request.interceptors.response.use(
(response) => response.data,
(error) => {
let msg = "";
if (error.response) {
const status = error.response.status;
switch (status) {
case 401:
msg = "Token 过期,请重新登录";
break;
case 403:
msg = "无权限访问";
break;
case 404:
msg = "请求地址不存在";
break;
case 500:
msg = "服务器错误,请稍后再试";
break;
default:
msg = "网络连接失败";
}
} else {
msg = "请求超时,请检查网络";
}
ElMessage.error(msg);
return Promise.reject(error);
}
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
拦截器作用:
- 统一处理 HTTP 状态码错误,如
401
、403
、404
。 - 使用
ElMessage
进行错误提示,提高用户体验。 - 确保
.then()
只会在成功时执行,避免错误请求污染逻辑。
# 7. 如何使用封装后的 axios
# 发送 GET
请求
import request from "@/utils/request";
request.get("/user/info").then((res) => {
console.log("用户信息:", res);
});
1
2
3
4
5
2
3
4
5
# 发送 POST
请求
request.post("/user/login", {
username: "admin",
password: "123456",
}).then((res) => {
console.log("登录成功:", res);
});
1
2
3
4
5
6
2
3
4
5
6
# 发送 DELETE
请求
request.delete("/user/delete", { data: { userId: 1 } }).then((res) => {
console.log("删除用户:", res);
});
1
2
3
2
3
# 8. 进一步优化
统一 API 返回数据格式
如果后端返回的数据结构不统一,可以在 request.ts
中统一格式化:
request.interceptors.response.use((response) => {
const res = response.data;
if (res.code !== 200) {
ElMessage.error(res.message || "请求失败");
return Promise.reject(res.message);
}
return res.data; // 只返回 data 字段,简化数据结构
});
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
这样,前端调用 API 时不需要额外解析 data
:
request.get("/user/info").then((userInfo) => {
console.log("用户信息:", userInfo);
});
1
2
3
2
3
编辑此页 (opens new window)