一文详解Vue3项目中的拦截器的作用和写法
作者:南雨北斗
在 Vue 3 项目中,拦截器(Interceptors)主要指 Axios 拦截器,它充当了前端应用与后端服务器之间的一个中间件层,其核心作用是在请求发送前或响应接收后,对数据进行统一拦截和处理,下面给大家具体说说,需要的朋友可以参考下
在 Vue 3 项目中,拦截器(Interceptors)主要指 Axios 拦截器,它充当了前端应用与后端服务器之间的一个中间件层。其核心作用是在请求发送前或响应接收后,对数据进行统一拦截和处理。
具体来说,Vue 3 项目中的拦截器主要有以下四大核心作用:
1. 请求拦截器(Request Interceptor)
在请求发送到服务器之前进行统一处理,避免在每个业务接口中重复编写相同的逻辑:
- 身份验证与授权:自动从本地存储(如
localStorage)读取 Token,并添加到每个请求的 Header 中,确保用户处于登录状态。 - 全局配置注入:统一设置请求超时时间、Content-Type 格式,或添加特定的公共请求参数。
- 全局 Loading 状态:在请求发出时触发全局的加载动画(Loading),提示用户正在获取数据。
- 数据预处理:对敏感请求参数进行加密处理,或格式化请求数据结构。
2. 响应拦截器(Response Interceptor)
在接收到服务器响应之后、业务代码处理数据之前进行统一处理:
- 统一数据格式化:剥离响应中无用的外层包装(如
{code: 200, msg: 'ok', data: {...}}),直接提取data返回给业务组件,简化业务代码。 - 全局 Loading 关闭:请求完成后,自动关闭之前开启的加载动画。
- 业务状态码处理:根据后端返回的自定义状态码(如
code != 200)进行统一拦截,例如提示错误信息或执行特定的业务逻辑。
3. 全局错误处理
拦截器可以捕获网络请求中出现的各类异常,并进行统一的兜底处理,大幅提升用户体验和代码的健壮性:
- HTTP 状态码处理:例如捕获
401 Unauthorized状态码,自动清除本地 Token 并重定向到登录页面;捕获403提示权限不足;捕获500提示服务器异常。 - 网络异常处理:处理断网、请求超时等网络错误,给出友好的全局 Toast 提示。
4. 提升代码质量与可维护性
- 消除冗余代码:将鉴权、错误提示、数据格式化等通用逻辑从具体的业务组件中抽离出来,使得组件代码更加纯粹和简洁。
- 增强复用性:只需在 Axios 实例中配置一次拦截器,整个 Vue 3 项目中的所有接口请求都会自动生效,极大地提高了开发效率和代码的可维护性。
补充说明:除了 Axios 拦截器,Vue 3 项目中还有 Vue Router 导航守卫(Navigation Guards)。它主要用于拦截页面的路由跳转,常用于页面级别的权限验证(如未登录禁止访问后台页面)、页面标题设置或数据预加载等。两者结合使用,可以构建非常完善的前端安全与交互体系。
下面是一个拦截器的例子:
1. Axios 请求/响应拦截器(核心)
通常在 src/utils/request.js 中封装,配合 ref 管理全局 Loading。
// src/utils/request.js
import axios from 'axios';
import { useUserStore } from '@/stores/user'; // Pinia 用户状态
import { ElMessage } from 'element-plus'; // UI 框架提示
// 1. 创建 axios 实例
const service = axios.create({
baseURL: import.meta.env.VITE_BASE_API, // 环境变量
timeout: 10000,
});
// 2. 请求拦截器
service.interceptors.request.use(
(config) => {
// 开启 Loading(配合 Element Plus 的 v-loading 指令全局控制)
// 这里可以添加一个全局 loading 计数器
// 自动添加 Token
const userStore = useUserStore();
if (userStore.token) {
config.headers.Authorization = `Bearer ${userStore.token}`;
}
// 处理特殊请求头(如 FormData)
if (config.data instanceof FormData) {
config.headers['Content-Type'] = 'multipart/form-data';
}
return config;
},
(error) => {
// 请求配置出错(如 URL 格式错误)
return Promise.reject(error);
}
);
// 3. 响应拦截器
service.interceptors.response.use(
(response) => {
// 关闭 Loading
// 后端约定 code===200 为成功
const { code, message, data } = response.data;
if (code === 200) {
return data; // 直接返回业务数据,简化调用
} else {
// 业务错误统一处理
ElMessage.error(message || '请求失败');
return Promise.reject(new Error(message));
}
},
(error) => {
// 网络超时、服务器 500 等错误
if (error.response) {
const { status } = error.response;
if (status === 401) {
// Token 失效:清除状态并跳转登录
const userStore = useUserStore();
userStore.logout();
window.location.href = '/login';
} else if (status === 403) {
ElMessage.error('没有权限访问');
} else {
ElMessage.error(error.response.data?.message || '系统错误');
}
} else if (error.message.includes('timeout')) {
ElMessage.error('请求超时,请稍后重试');
} else {
ElMessage.error('网络异常,请检查连接');
}
return Promise.reject(error);
}
);
export default service;2. 组件级渲染错误拦截(onErrorCaptured)
在父组件中捕获子组件异常,防止白屏。
<template>
<ChildComponent />
</template>
<script setup>
import { onErrorCaptured } from 'vue';
import { ElMessage } from 'element-plus';
// 捕获后代组件的错误
onErrorCaptured((err, instance, info) => {
console.error('子组件错误:', err, info);
ElMessage.error('页面渲染出现异常');
// 返回 false 阻止错误继续向上传播
return false;
});
</script>3. 应用全局错误拦截(app.config.errorHandler)
在 main.js 中注册,捕获所有未被组件捕获的错误。
// main.js
import { createApp } from 'vue';
import App from './App.vue';
const app = createApp(App);
app.config.errorHandler = (err, vm, info) => {
console.error('全局捕获错误:', err, info);
// 上报到 Sentry 或自己的日志平台
// reportErrorToServer(err);
};
app.mount('#app');4. 路由导航守卫(路由拦截)
在 src/router/index.js 中配置,用于权限控制。
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import { useUserStore } from '@/stores/user';
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/login', component: () => import('@/views/Login.vue') },
{ path: '/dashboard', component: () => import('@/views/Dashboard.vue'), meta: { requiresAuth: true } },
],
});
// 全局前置守卫
router.beforeEach((to, from, next) => {
const userStore = useUserStore();
const isLoggedIn = !!userStore.token;
if (to.meta.requiresAuth) {
if (isLoggedIn) {
next(); // 已登录,放行
} else {
next({ path: '/login', query: { redirect: to.fullPath } }); // 未登录,跳转登录
}
} else {
// 如果已登录且访问登录页,直接跳转首页
if (to.path === '/login' && isLoggedIn) {
next({ path: '/' });
} else {
next();
}
}
});
export default router;5. 在组件中使用封装好的请求
<script setup>
import request from '@/utils/request';
const fetchData = async () => {
try {
// 直接拿到 data,无需再解构
const res = await request.get('/user/info');
console.log(res);
} catch (error) {
// 拦截器已经提示了错误,这里只需处理特殊逻辑
console.log('请求失败');
}
};
</script>关键点总结
| 拦截器类型 | 核心作用 | 常见写法位置 |
|---|---|---|
| Axios 请求拦截 | 加 Token、启动 Loading | request.js |
| Axios 响应拦截 | 解构数据、统一错误提示、401跳转 | request.js |
| 组件错误拦截 | 捕获子组件渲染异常 | 父组件 onErrorCaptured |
| 全局错误拦截 | 兜底所有未捕获错误 | main.js |
| 路由拦截 | 登录鉴权、页面权限控制 | router/index.js |
到此这篇关于一文详解Vue3项目中的拦截器的作用和写法的文章就介绍到这了,更多相关Vue3拦截器作用和写法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
