引言:为什么选择Axios?
在 Vue3 项目开发中,数据请求是一个常见的需求。虽然浏览器本身提供了 fetch API,但 Axios 由于其强大的功能,比如拦截器、自动 JSON 转换、请求取消等,成为了大多数 Vue 开发者的首选工具。本文将讲解如何在 Vue3 中高效使用 Axios。
一、项目初始化与基础配置
1.1 安装与引入
npm install axios
或
yarn add axios
1.2 创建Axios实例
utils/request.js
javascript
import axios from 'axios';
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_API_BASE_URL, // 从环境变量读取
timeout: 15000, // 请求超时时间
headers: {
'Content-Type': 'application/json;charset=utf-8'
}
});
export default service;
1.3 全局挂载(可选)
main.js
javascript
import { createApp } from 'vue';
import App from './App.vue';
import axios from './utils/request';
const app = createApp(App);
// 全局挂载
app.config.globalProperties.$axios = axios;
app.mount('#app');
二、核心功能实现
2.1 请求拦截器:统一处理请求
使用请求拦截器来进行一些统一的操作,比如添加 Token 或显示 loading:
javascript
service.interceptors.request.use(config => {
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
if (config.method === 'get') {
config.params = {
...config.params,
_t: Date.now() // 防止缓存
};
}
if (config.showLoading !== false) {
showLoading(); // 显示 loading
}
return config;
}, error => Promise.reject(error));
2.2 响应拦截器:统一处理响应
响应拦截器可以统一处理成功或失败的请求结果:
javascript
service.interceptors.response.use(response => {
hideLoading(); // 隐藏 loading
const res = response.data;
if (res.code === 200) {
return res.data; // 返回数据
} else {
handleBusinessError(res.code, res.message);
return Promise.reject(new Error(res.message || 'Error'));
}
}, error => {
hideLoading(); // 隐藏 loading
handleError(error); // 处理错误
return Promise.reject(error);
});
三、封装高级请求函数
3.1 通用请求方法封装
封装一个通用的请求函数,支持各种请求方式:
javascript
import service from '../utils/request';
export function request(options) {
return new Promise((resolve, reject) => {
service(options)
.then(response => resolve(response))
.catch(error => reject(error));
});
}
export function get(url, params = {}, config = {}) {
return request({
url,
method: 'GET',
params,
...config
});
}
export function post(url, data = {}, config = {}) {
return request({
url,
method: 'POST',
data,
...config
});
}
3.2 业务API模块化
通过模块化管理 API,例如用户相关接口:
javascript
import { get, post } from './http';
export const userApi = {
login(data) {
return post('/user/login', data);
},
getUserInfo(params) {
return get('/user/info', params);
},
updateUserInfo(data) {
return post('/user/update', data);
},
deleteUser(id) {
return post(`/user/${id}/delete`);
}
};
四、在Vue3组件中使用
4.1 Composition API 方式
使用 Composition API 获取并展示数据:
javascript
<template>
<div>
<ul>
<li v-for="user in users" :key="user.id">{{ user.name }} - {{ user.email }}</li>
</ul>
<button @click="loadUsers" :disabled="loading">{{ loading ? '加载中...' : '加载用户' }}</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { userApi } from '../api/user';
const users = ref([]);
const loading = ref(false);
const error = ref(null);
const loadUsers = async () => {
try {
loading.value = true;
const response = await userApi.getUserList({ page: 1, size: 10 });
users.value = response.list;
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
};
onMounted(loadUsers);
</script>
4.2 Options API 方式
如果使用 Options API,代码会类似这样:
javascript
<script>
import { userApi } from '../api/user';
export default {
name: 'UserComponent',
data() {
return {
users: [],
loading: false,
error: null
};
},
mounted() {
this.loadUsers();
},
methods: {
async loadUsers() {
try {
this.loading = true;
const response = await userApi.getUserList({ page: 1, size: 10 });
this.users = response.list;
} catch (error) {
this.error = error.message;
} finally {
this.loading = false;
}
}
}
};
</script>
五、高级特性应用
5.1 请求取消功能
Axios 支持取消请求。可以通过 CancelToken 来中止请求:
javascript
import axios from 'axios';
const CancelToken = axios.CancelToken;
let cancel;
function searchUsers(keyword) {
if (cancel) {
cancel('取消上一个请求');
}
return userApi.getUserList({ keyword, page: 1, size: 10 }, {
cancelToken: new CancelToken(c => cancel = c)
});
}
5.2 请求重试机制
封装带重试机制的请求,适用于网络错误或服务器错误:
javascript
export function requestWithRetry(config, maxRetries = 3) {
return new Promise((resolve, reject) => {
const attempt = (retryCount) => {
service(config)
.then(resolve)
.catch(error => {
if (retryCount < maxRetries && shouldRetry(error)) {
setTimeout(() => attempt(retryCount + 1), 1000 * Math.pow(2, retryCount)); // 指数退避
} else {
reject(error);
}
});
};
attempt(0);
});
}
function shouldRetry(error) {
return !error.response || error.response.status >= 500;
}
六、TypeScript支持
6.1 类型定义
在 TypeScript 中可以使用类型定义来确保请求数据的一致性:
TypeScript
export interface ApiResponse<T = any> {
code: number;
message: string;
data: T;
}
export interface PageParams {
page: number;
size: number;
keyword?: string;
}
6.2 类型安全的请求封装
为请求函数添加类型支持,提高开发时的类型安全:
TypeScript
export async function typedRequest<T = any>(
config: AxiosRequestConfig
): Promise<T> {
const response: AxiosResponse<ApiResponse<T>> = await service(config);
return response.data.data;
}
七、总结
通过合理封装和配置 Axios,不仅可以轻松地进行 HTTP 请求,还能利用拦截器、请求取消和重试机制等高级功能,提高项目的稳定性和用户体验。