Vue 3 项目中的拦截器的作用和写法(动态设置响应头适配表单文件上传)

160 阅读3分钟

在 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)。它主要用于拦截页面的路由跳转,常用于页面级别的权限验证(如未登录禁止访问后台页面)、页面标题设置或数据预加载等。两者结合使用,可以构建非常完善的前端安全与交互体系。

下面是一个拦截器的例子:

src/api/request.js

import axios from 'axios'
// 创建axios实例
const service = axios.create({
  baseURL: '/api', // 公共基础地址
  timeout: 10000, // 请求超时时间 10秒
})

// 请求拦截器:发请求之前做处理,比如携带token
service.interceptors.request.use(
config => {
  // 动态判断:只有不是FormData,才设置json头
  if (!(config.data instanceof FormData)) {
    config.headers['Content-Type'] = 'application/json;charset=utf-8'
  }
  // 示例:如果本地有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 => {
  // 直接返回data,组件不用每次写 resp.data
  return response.data
},
error => {
  // 统一错误处理:打印错误、弹窗提示等
  console.error('请求异常:', error)
  // http状态码判断
  if (error.response) {
    switch (error.response.status) {
      case 401:
        console.log('未授权,请登录')
        break
      case 404:
        console.log('接口地址不存在')
        break
      case 500:
        console.log('服务器内部错误')
        break
    }
  }
  return Promise.reject(error)
}
)

export default service