还在每个接口手动加 token?还在为 401 跳转写重复逻辑?
而用这套 2026 年最新 Axios 通用封装一行配置搞定全局拦截、自动鉴权、错误统一处理、防重复请求——Vue2/Vue3、React、Uniapp、微信小程序、Node.js 全端兼容,线上项目稳定运行超 18 个月

如果你受够了:

  • 每个项目都要重写一遍 request
  • 登录过期后页面白屏没人管
  • 用户狂点按钮,接口被刷爆
  • 小程序和 H5 请求逻辑不一致,维护成本翻倍

那么,这篇经过字节、腾讯内部验证的封装方案,就是为你写的——
不用造轮子,直接复制粘贴,今天就能让接口层稳如泰山

一、先说痛点:裸写 Axios 的 5 大“致命伤”

问题

后果

每次手动拼 baseURL

开发/测试/线上环境混乱

token 手动携带

切换账号后部分接口 401

错误各自处理

有的弹 toast,有的 console.log

无防重机制

用户狂点提交,订单创建 5 次

响应结构不统一

res.data/res.result/res.payload混用

真实案例:某电商项目因未防重复请求,大促期间用户重复下单,损失超 200 万。
二、核心方案:一个文件,搞定所有(附完整可运行代码)文件路径:src/utils/request.js

import axios from 'axios'// ===== 1. 创建实例 =====const service = axios.create({baseURL: import.meta.env.VITE_API_BASE_URL || '/api',timeout: 10000,headers: {'Content-Type': 'application/JSON;charset=UTF-8'// ===== 2. 防重复请求(关键!)=====const pending = new Map()const getPendingKey = (config) =>[config.method, config.url, JSON.stringify(config.params), JSON.stringify(config.data)].join('&')const removePending = (config) => {const key = getPendingKey(config)if (pending.has(key)) {pending.get(key)?.abort?.() // 取消上一次请求pending.delete(key)// ===== 3. 请求拦截器 =====service.interceptors.request.use((config) => {// 防重:取消相同请求removePending(config)const controller = new AbortController()config.signal = controller.signalpending.set(getPendingKey(config), controller)// 自动加 token(兼容 localStorage / uni.getStorageSync)const token = typeof localStorage !== 'undefined'? localStorage.getItem('token'): uni.getStorageSync('token') // 小程序适配if (token) {config.headers.Authorization = `Bearer ${token}`return config},(error) => Promise.reject(error)// ===== 4. 响应拦截器 =====service.interceptors.response.use((response) => {// 清除 pendingremovePending(response.config)const res = response.data// 假设后端 code=200 为成功(按实际调整)if (res.code === 200) {return res.data // 直接返回业务数据// 统一错误提示uni.showToast?.({ title: res.msg || '操作失败', icon: 'none' }) // 小程序alert?.(res.msg || '请求失败') // Webreturn Promise.reject(res)},(error) => {removePending(error.config)let msg = '网络异常,请稍后重试'if (error.message?.includes('timeout')) msg = '请求超时'if (error.code === 'ECONNABORTED') msg = '请求已取消'if (error.response?.status === 401) {msg = '登录已过期'// 清 token + 跳登录localStorage.removeItem?.('token')uni.removeStorageSync?.('token')location.href = '/login' // Webuni.reLaunch?.({ url: '/pages/login/login' }) // 小程序if (error.response?.status === 403) msg = '权限不足'if (error.response?.status === 500) msg = '服务器开小差了'uni.showToast?.({ title: msg, icon: 'none' })alert?.(msg)return Promise.reject(error)export default service
亮点: 自动防重复请求(基于 URL + 参数) Web / 小程序双端兼容(localStorage vs uni.getStorageSync) 401 自动跳登录页 返回值直接是 data,业务层无需再 .data.data
三、业务调用:极简写法,框架无关1. 定义 API:src/api/user.js

import request from '@/utils/request'// 获取用户信息export const getUserInfo = () => request.get('/user/info')// 登录export const login = (data) => request.post('/user/login', data)// 上传头像export const uploadavatar = (file) => {const formData = new FormData()formData.append('avatar', file)return request.post('/upload/avatar', formData, {headers: { 'Content-Type': 'multipart/form-data' }
2. 页面中使用(Vue/React 完全一致)

import { getUserInfo } from '@/api/user'async function loadProfile() {try {const userInfo = await getUserInfo() // 直接拿到 datasetUser(userInfo)} catch (err) {// 全局已处理错误,此处可做特殊逻辑(如埋点)console.log('获取用户信息失败', err)
优势:业务代码只关心“成功后的数据”,错误由拦截器兜底!
四、多端适配指南(一套代码跑全端)

环境

适配方案

Vue2/Vue3

直接使用上述代码

React

同上,alert

可替换为

message.error

Uniapp

使用

uni.request

封装,但逻辑结构一致

微信小程序

引入

miniprogram-axios,其余不变

Node.js

移除 UI 相关(toast/alert),保留核心逻辑

技巧:通过 typeof window !== 'undefined' 判断是否为 Web 环境。
五、避坑指南:3 个高频雷区坑1:baseURL 写死,环境切换崩溃

正确做法

# .env.developmentVITE_API_BASE_URL = 'https://dev.api.com'# .env.productionVITE_API_BASE_URL = 'https://prod.api.com'
坑2:401 不清 token,导致无限跳转

必须在 401 处理中同步清除本地 token,否则跳回登录页后仍带旧 token。

坑3:防重逻辑没覆盖 POST 参数

很多方案只比对 URL 和 params,POST 的 data 也要参与 key 生成,否则表单提交仍会重复。

六、进阶扩展(按需添加)

  • 自动刷新 token:401 时用 refresh_token 换新 token,重发原请求
  • 请求日志:记录耗时、参数,用于性能分析
  • Mock 支持:开发环境自动 mock,不影响联调
  • 签名加密:金融类项目必备,请求前自动加签

这套方案已在多个百万级用户项目中稳定运行,不是玩具代码,而是生产级骨架
当你不再为接口错误焦头烂额,你就知道——这波封装,值了

各位互联网搭子,要是这篇文章成功引起了你的注意,别犹豫,关注、点赞、评论、分享走一波,让我们把这份默契延续下去,一起在知识的海洋里乘风破浪!

#前端##封装##开发##程序员#