Vue+Axios热更新导致响应拦截器重复注册问题的解决方案

 更新时间:2026年02月07日 09:12:07   作者:Mr Xu_  
在使用 Vue 3(或 Vue 2)配合 Vite / Webpack 开发时,我们经常会遇到一个隐性陷阱:开发环境下热更新会导致 Axios 响应拦截器被重复注册,因此本文将结合实际代码,深入剖析该问题的成因,并介绍一种稳定、可靠的解决方案,需要的朋友可以参考下

在使用 Vue 3(或 Vue 2)配合 Vite / Webpack 开发时,我们经常会遇到一个“隐性陷阱”:开发环境下热更新(HMR, Hot Module Replacement)会导致 Axios 响应拦截器被重复注册。这个问题在控制台中表现为接口响应日志被多次打印、错误提示重复弹出,甚至引发逻辑混乱。

本文将结合实际代码,深入剖析该问题的成因,并介绍一种稳定、可靠的解决方案。

一、问题现象

假设我们在 request.js 中配置了 Axios 的响应拦截器:

// request.js
import axios from 'axios'
 
axios.interceptors.response.use(
  (res) => {
    console.log('响应拦截器执行')
    // 处理响应逻辑...
    return res.data
  },
  (err) => {
    // 错误处理...
    return Promise.reject(err)
  }
)

当你在开发过程中修改任意文件触发热更新后,再次发起请求,会发现控制台中 "响应拦截器执行" 被打印了 两次、四次甚至更多次

这说明:每次热更新都会重新执行 request.js 模块,从而重复注册新的拦截器。而旧的拦截器并未被清除,导致多个拦截器实例同时生效。

二、错误尝试:使用局部变量控制

很多开发者第一反应是用一个布尔变量来防止重复注册:

let isResponseRegistered = false
 
if (!isResponseRegistered) {
  axios.interceptors.response.use(...)
  isResponseRegistered = true
}

但你会发现,这个方案在热更新下依然失效——控制台还是打印了两次日志。

为什么?

因为 热更新会重新执行整个模块(包括变量声明)。也就是说,每次 HMR 触发时,isResponseRegistered 都会被重置为 false,于是拦截器又被注册了一次。

关键点:模块级变量在热更新时会被重新初始化,无法跨更新周期保持状态。

三、正确方案:将标志挂载到 Axios 实例上

要解决这个问题,必须使用一个 不会被热更新重置的对象属性 来记录是否已注册拦截器。

Axios 本身是一个对象(函数对象),我们可以直接在其上挂载自定义属性:

// 防止热更新重复注册响应拦截器
if (!axios.__myResponseInterceptor__) {
  axios.interceptors.response.use(
    (res) => {
      console.log('响应拦截器执行')
      // ...处理逻辑
      return res.data
    },
    (err) => {
      return Promise.reject(err)
    }
  )
  axios.__myResponseInterceptor__ = true // 标记已注册
}

为什么这个方案有效?

  • axios 是从 node_modules 引入的模块,在 HMR 中 通常不会被重新加载(属于“稳定的依赖”)。
  • 因此,挂载在 axios 上的属性 __myResponseInterceptor__ 在热更新期间保持不变
  • 即使 request.js 被反复执行,也能准确判断拦截器是否已存在。

这是一种被社区广泛验证的有效做法,类似方案也用于防止重复注册全局组件、插件等。

四、完整代码示例(来自实际项目)

以下是从你提供的 request.js 中提取的核心逻辑:

// 防止响应拦截器被重复注册
if (!axios.__myResponseInterceptor__) {
  axios.interceptors.response.use(
    (res) => {
      // 二进制数据直接返回
      if (res.request?.responseType === 'blob' || ...) {
        return res.data
      }
      if (!res.data) {
        return { code: 200, data: null, message: '热更新中' }
      }
      switch (Number(res.data.code)) {
        case 401:
          router.push('/login')
          break
        case 200:
          if (res.data.token) {
            localStorage.setItem('token', res.data.token)
          }
          return res.data
        default:
          return res.data
      }
    },
    (err) => {
      return Promise.reject(err)
    }
  )
  axios.__myResponseInterceptor__ = true // 关键:标记已注册
}

该方案成功解决了热更新下的重复注册问题,且不影响生产环境(生产环境无 HMR,只执行一次)。

五、其他可行方案(补充)

使用 import.meta.hot?.accept() 手动管理副作用(Vite 特有)
可在模块卸载时移除拦截器,但实现复杂,不推荐。

将拦截器注册移到 main.js 或入口文件
减少被 HMR 影响的概率,但若入口文件也被更新,仍可能失效。

使用单例模式封装 Axios 实例
例如导出一个 createAxiosInstance() 函数,并缓存实例。但需确保调用方不重复创建。

相比之下,挂载标志位到 axios 对象上是最简单、可靠、低侵入性的方案。

六、总结

方案是否有效原因
局部变量 let flag = false热更新重置变量
挂载到 axios 对象上axios 模块稳定,属性持久
移到 main.js⚠️降低概率,但非根治
手动 HMR 清理✅ 但复杂需要监听模块更新事件

最佳实践:在开发 Axios 封装库时,务必考虑 HMR 场景,使用 axios.__xxx__ 标志位防止重复注册拦截器。

希望本文能帮助你彻底理解并解决这一“开发期幽灵 bug”。

到此这篇关于Vue+Axios热更新导致响应拦截器重复注册问题的解决方案的文章就介绍到这了,更多相关Vue Axios热更新导致拦截器重复注册内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 在Vue项目中引入JQuery-ui插件的讲解

    在Vue项目中引入JQuery-ui插件的讲解

    今天小编就为大家分享一篇关于在Vue项目中引入JQuery-ui插件的讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01
  • element tab标签管理路由页面的项目实践

    element tab标签管理路由页面的项目实践

    本文主要介绍了element tab标签管理路由页面的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • Vue Promise解决回调地狱问题实现方法

    Vue Promise解决回调地狱问题实现方法

    这篇文章主要介绍了Vue Promise解决回调地狱问题,总的来说这并不是一道难题,那为什么要拿出这道题介绍?拿出这道题真正想要传达的是解题的思路,以及不断优化探寻最优解的过程。希望通过这道题能给你带来一种解题优化的思路
    2023-01-01
  • Vue项目中接口调用的详细讲解

    Vue项目中接口调用的详细讲解

    应公司需求,接口需要对接vue,记录一下碰到的问题,下面这篇文章主要给大家介绍了关于Vue项目中接口调用的详细讲解,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • 基于Vue的文字跑马灯组件(npm 组件包)

    基于Vue的文字跑马灯组件(npm 组件包)

    这篇文章主要介绍了基于Vue的文字跑马灯组件(npm 组件包),需要的朋友可以参考下
    2017-05-05
  • vue iview封装模态框的方法

    vue iview封装模态框的方法

    这篇文章主要为大家详细介绍了vue iview封装模态框的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07
  • vue可视化表单设计器自定义组件使用方法

    vue可视化表单设计器自定义组件使用方法

    Vue前端开发中表单组件是排在前三的高频使用的组件,下面这篇文章主要给大家介绍了关于vue可视化表单设计器自定义组件使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • 浅谈vue中$event理解和框架中在包含默认值外传参

    浅谈vue中$event理解和框架中在包含默认值外传参

    这篇文章主要介绍了浅谈vue中$event理解和框架中在包含默认值外传参,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • 浅谈Vant-list 上拉加载及下拉刷新的问题

    浅谈Vant-list 上拉加载及下拉刷新的问题

    这篇文章主要介绍了浅谈Vant-list 上拉加载及下拉刷新的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Element-ui Drawer抽屉按需引入基础使用

    Element-ui Drawer抽屉按需引入基础使用

    这篇文章主要为大家介绍了Element-ui Drawer抽屉按需引入基础使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-07-07

最新评论