嘿,老铁!是不是还在Vue项目里跟网络请求较劲?每次看到fetch那冗长的代码就想砸键盘?别急,今天我要给你安利一个神器——axios,这玩意儿能让你的网络请求变得像喝奶茶一样丝滑!
为什么是axios,而不是fetch?
先说说为啥要选axios。fetch不是不能用,但它就像个毛坯房,啥都得自己装修。比如,fetch默认不会处理错误,得手动检查response.ok;返回的数据得自己转JSON;还没有请求超时和取消功能……想想就头大!
axios就不一样了,它是个精装房,拎包入住!自动转换JSON数据、智能处理错误、请求响应拦截、CSRF防护、甚至还能取消请求——这些功能开箱即用,爽不爽?
举个栗子,用fetch发个POST请求得这么写:
fetch('/api/user', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name: '小明',
age: 18
})
})
.then(response => {
if (!response.ok) {
throw new Error('网络响应不正常');
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('出错啦:', error));
而用axios,简洁到飞起:
axios.post('/api/user', {
name: '小明',
age: 18
})
.then(response => console.log(response.data))
.catch(error => console.error('出错啦:', error));
看到没?代码少了一半,可读性还更强!这就是为什么Vue社区几乎清一色选择axios的原因。
手把手教你安装配置axios
好了,口水话不多说,咱们直接上手!在你的Vue项目里安装axios:
npm install axios
# 或者
yarn add axios
安装完怎么用?有三种姿势,从菜鸟到高手任君选择:
姿势一:简单粗暴式 - 适合小项目
直接在组件里引入就用:
import axios from 'axios';
export default {
methods: {
async fetchUser() {
try {
const response = await axios.get('/api/user/123');
this.user = response.data;
} catch (error) {
console.error('获取用户失败:', error);
}
}
}
}
姿势二:全局注册式 - 推荐大多数项目
在main.js里配置,整个项目都能用:
import { createApp } from 'vue';
import axios from 'axios';
import App from './App.vue';
const app = createApp(App);
// 全局配置axios
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.timeout = 5000;
// 挂载到Vue原型上,组件内直接用this.$axios
app.config.globalProperties.$axios = axios;
app.mount('#app');
然后在组件里就能愉快地使用了:
export default {
methods: {
async getUser() {
try {
const response = await this.$axios.get('/user/123');
return response.data;
} catch (error) {
this.$message.error('获取数据失败');
}
}
}
}
姿势三:封装服务式 - 企业级大项目必备
创建src/api/request.js文件进行高级封装:
import axios from 'axios';
import { Message } from 'element-ui'; // 如果你用了UI框架
// 创建axios实例
const service = axios.create({
baseURL: process.env.VUE_APP_BASE_API,
timeout: 10000,
});
// 请求拦截器 - 发请求前做什么
service.interceptors.request.use(
config => {
// 在发送请求前添加token
const token = localStorage.getItem('token');
if (token) {
config.headers['Authorization'] = `Bearer ${token}`;
}
return config;
},
error => {
return Promise.reject(error);
}
);
// 响应拦截器 - 收到响应后做什么
service.interceptors.response.use(
response => {
const res = response.data;
// 根据后端返回码判断请求状态
if (res.code !== 200) {
Message.error(res.message || '请求失败');
return Promise.reject(new Error(res.message || 'Error'));
} else {
return res;
}
},
error => {
// 处理HTTP网络错误
let message = '网络异常,请稍后重试';
if (error.response) {
switch (error.response.status) {
case 401:
message = '未授权,请重新登录';
// 跳转到登录页
break;
case 403:
message = '拒绝访问';
break;
case 404:
message = '请求地址不存在';
break;
case 500:
message = '服务器内部错误';
break;
default:
message = `连接错误${error.response.status}`;
}
}
Message.error(message);
return Promise.reject(error);
}
);
export default service;
然后在具体的API模块中使用:
// src/api/user.js
import request from './request';
export function getUserInfo(userId) {
return request({
url: `/user/${userId}`,
method: 'get'
});
}
export function updateUser(userData) {
return request({
url: '/user/update',
method: 'post',
data: userData
});
}
实战!完整用户管理系统示例
光说不练假把式,来看个完整的用户管理组件:
<template>
<div class="user-management">
<h2>用户管理系统</h2>
<!-- 查询区域 -->
<div class="search-box">
<el-input v-model="searchKeyword" placeholder="输入用户名搜索" style="width: 300px" />
<el-button type="primary" @click="handleSearch">搜索</el-button>
<el-button @click="handleAdd">新增用户</el-button>
</div>
<!-- 用户列表 -->
<el-table :data="userList" v-loading="loading">
<el-table-column prop="id" label="ID" width="80" />
<el-table-column prop="name" label="姓名" />
<el-table-column prop="email" label="邮箱" />
<el-table-column prop="createTime" label="创建时间" />
<el-table-column label="操作">
<template #default="scope">
<el-button size="small" @click="handleEdit(scope.row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(scope.row.id)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
:current-page="pagination.current"
:page-size="pagination.size"
:total="pagination.total"
@current-change="handlePageChange"
layout="total, prev, pager, next, jumper"
/>
<!-- 新增/编辑对话框 -->
<el-dialog :title="dialogTitle" v-model="dialogVisible">
<el-form :model="userForm" :rules="formRules" ref="userFormRef" label-width="80px">
<el-form-item label="姓名" prop="name">
<el-input v-model="userForm.name" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-input v-model="userForm.email" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSubmit">确定</el-button>
</template>
</el-dialog>
</div>
</template>
<script>
import { getUserList, createUser, updateUser, deleteUser } from '@/api/user';
export default {
name: 'UserManagement',
data() {
return {
searchKeyword: '',
loading: false,
userList: [],
pagination: {
current: 1,
size: 10,
total: 0
},
dialogVisible: false,
dialogType: 'add', // 'add' or 'edit'
userForm: {
id: null,
name: '',
email: ''
},
formRules: {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '邮箱格式不正确', trigger: 'blur' }
]
}
};
},
computed: {
dialogTitle() {
return this.dialogType === 'add' ? '新增用户' : '编辑用户';
}
},
mounted() {
this.loadUserList();
},
methods: {
// 加载用户列表
async loadUserList() {
this.loading = true;
try {
const params = {
page: this.pagination.current,
size: this.pagination.size,
keyword: this.searchKeyword
};
const result = await getUserList(params);
this.userList = result.data.list;
this.pagination.total = result.data.total;
} catch (error) {
console.error('加载用户列表失败:', error);
} finally {
this.loading = false;
}
},
// 搜索用户
handleSearch() {
this.pagination.current = 1;
this.loadUserList();
},
// 新增用户
handleAdd() {
this.dialogType = 'add';
this.userForm = { id: null, name: '', email: '' };
this.dialogVisible = true;
},
// 编辑用户
handleEdit(user) {
this.dialogType = 'edit';
this.userForm = { ...user };
this.dialogVisible = true;
},
// 提交表单
async handleSubmit() {
try {
await this.$refs.userFormRef.validate();
if (this.dialogType === 'add') {
await createUser(this.userForm);
this.$message.success('新增用户成功');
} else {
await updateUser(this.userForm);
this.$message.success('更新用户成功');
}
this.dialogVisible = false;
this.loadUserList(); // 重新加载列表
} catch (error) {
if (error.fields) {
this.$message.warning('请完善表单信息');
} else {
console.error('提交失败:', error);
}
}
},
// 删除用户
async handleDelete(userId) {
try {
await this.$confirm('确定删除该用户吗?', '提示', {
type: 'warning'
});
await deleteUser(userId);
this.$message.success('删除用户成功');
this.loadUserList();
} catch (error) {
if (error === 'cancel') {
this.$message.info('已取消删除');
} else {
console.error('删除失败:', error);
}
}
},
// 分页变化
handlePageChange(currentPage) {
this.pagination.current = currentPage;
this.loadUserList();
}
}
};
</script>
<style scoped>
.user-management {
padding: 20px;
}
.search-box {
margin-bottom: 20px;
}
</style>
高级技巧:让你的请求更优雅
1. 请求取消 - 告别无用请求
在搜索场景中,用户连续输入时,前一个请求可能还没返回,后一个请求就发出了。这时候需要取消前一个请求:
// 在API文件中
let cancelRequest = null;
export function searchUsers(keyword) {
// 如果已有请求在进行,先取消
if (cancelRequest) {
cancelRequest('取消重复请求');
}
return request({
url: '/user/search',
method: 'get',
params: { keyword },
cancelToken: new axios.CancelToken(function executor(c) {
cancelRequest = c;
})
});
}
2. 自动重试 - 增强用户体验
对于某些临时性错误,可以设置自动重试:
// 重试函数
function retryRequest(axiosInstance, retryCount = 3) {
return async function(config) {
let lastError;
for (let i = 0; i < retryCount; i++) {
try {
return await axiosInstance(config);
} catch (error) {
lastError = error;
// 如果是网络错误或5xx错误,进行重试
if (!error.response || error.response.status >= 500) {
console.warn(`请求失败,第${i + 1}次重试...`);
// 等待一段时间再重试
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
continue;
}
break;
}
}
throw lastError;
};
}
// 使用示例
const apiWithRetry = retryRequest(axios);
const result = await apiWithRetry({ url: '/api/data' });
3. 请求缓存 - 提升性能
对于一些不常变化的数据,可以添加缓存:
const cache = new Map();
export function getCachedData(url, forceRefresh = false) {
// 强制刷新或缓存不存在时重新请求
if (forceRefresh || !cache.has(url)) {
const promise = axios.get(url).catch(error => {
// 请求失败时清除缓存
cache.delete(url);
throw error;
});
cache.set(url, promise);
}
return cache.get(url);
}
常见坑位及填坑指南
坑1:this指向问题
在axios回调函数中,this可能不是Vue实例。解决方案:使用箭头函数或bind。
// 错误写法
axios.get('/api/data').then(function(response) {
this.data = response.data; // this不是Vue实例!
});
// 正确写法 - 箭头函数
axios.get('/api/data').then(response => {
this.data = response.data;
});
// 正确写法 - bind
axios.get('/api/data').then(function(response) {
this.data = response.data;
}.bind(this));
坑2:Vue 3的响应式更新
在Vue 3中,直接给响应式对象赋值可能不会触发更新:
// 可能不会触发更新
const state = reactive({ user: {} });
axios.get('/api/user').then(response => {
state.user = response.data; // 直接替换可能有问题
});
// 更好的做法 - 逐个属性赋值
axios.get('/api/user').then(response => {
Object.assign(state.user, response.data);
});
// 或者使用ref
const user = ref({});
axios.get('/api/user').then(response => {
user.value = response.data; // 这样是可以的
});
结语
axios在Vue项目中的地位,就像奶茶里的珍珠——没有它也能喝,但有了它才完整!从简单的GET请求到复杂的企业级应用,axios都能优雅应对。
记住,好的网络请求处理不仅能让代码更整洁,还能显著提升用户体验。现在就去你的Vue项目里试试axios吧,保证让你直呼"真香"!

被折叠的 条评论
为什么被折叠?



