关于请求封装中关于错误提示的三种实践方案:UI 直出 vs 全局 Handler vs EventBus

🛠️ React 项目中接口错误提示的三种实践方案:UI 直出 vs 全局 Handler vs EventBus

在实际开发中,我们经常需要在请求失败时展示统一的错误提示。无论是 axiosfetch,只要涉及封装请求,就绕不开"请求错误如何提示用户"的话题。

本文基于本人项目实战,梳理了三种常见实现方案,从简单到高级一应俱全,供你按需选用。


✅ 场景说明

  • 使用 React(任意框架均可类比)
  • 使用 axios 封装请求
  • 错误码中有业务错误(如 code: 1,而非 HTTP 错误)
  • 希望在请求失败时展示 toast 或其他提示

🔧 三种方案概览

方案 简介 优点 缺点 适用项目
方案一 直接在 axios 中调用 UI 快速简单 UI 耦合严重,不易维护 demo、PoC、小项目
方案二 抽出全局 UI handler 注入 UI 解耦、可控性强 初始化要求高 中小项目
方案三 使用 EventBus 派发事件 最灵活、可统一处理复杂错误码 代码复杂度略高 中大型项目、多人协作项目

🚀 方案一:直接调用 UI 组件(耦合强)

✅ 示例代码

javascript 复制代码
import axios from 'axios'
import { message } from 'antd'

const request = axios.create()

request.interceptors.response.use(
  res => {
    if (res.data.code !== 0) {
      message.error(res.data.message || '请求失败')
      return Promise.reject(res.data)
    }
    return res.data
  },
  err => {
    message.error(err.message || '网络错误')
    return Promise.reject(err)
  }
)

✅ 优点

  • 上手快,适合小项目
  • 没有额外封装成本

❌ 缺点

  • UI 库(如 antd、element)直接耦合进 request 层
  • 未来更换 UI 库代价大

✨ 方案二:全局 UI Handler 注入式调用(中等耦合)

✅ 核心思路

将 UI 提示通过 setUIHandler() 注入,request.ts 内只调用 handler,解耦 UI。

✅ 实现步骤

1. 定义 UI Handler 工具
javascript 复制代码
// utils/globalUI.ts
export type UIHandler = {
  error: (msg: string) => void
  success?: (msg: string) => void
}

let handler: UIHandler | null = null

export function setUIHandler(h: UIHandler) {
  handler = h
}

export function getUIHandler(): UIHandler {
  if (!handler) throw new Error('UIHandler 未初始化')
  return handler
}
2. 在 request.ts 中使用
javascript 复制代码
import axios from 'axios'
import { getUIHandler } from './globalUI'

const request = axios.create()

request.interceptors.response.use(
  res => {
    if (res.data.code !== 0) {
      getUIHandler().error(res.data.message || '请求失败')
      return Promise.reject(res.data)
    }
    return res.data
  },
  err => {
    getUIHandler().error(err.message || '网络错误')
    return Promise.reject(err)
  }
)
3. 在 App 入口注入 UI 实现
javascript 复制代码
// App.tsx
import { message } from 'antd'
import { setUIHandler } from './utils/globalUI'

setUIHandler({
  error: msg => message.error(msg),
})

✅ 优点

  • UI 解耦
  • 支持切换提示方式、mock、测试
  • 适合中型项目

❌ 缺点

  • 需要额外初始化步骤
  • 无法处理组件内自定义提示(需手动处理)

📦 方案三:基于 EventBus 的解耦提示(推荐用于复杂场景)

✅ 核心思路

  • 使用 mitteventemitter3 或自定义 EventBus
  • 请求失败时发送事件,由 UI 组件统一监听提示

✅ 示例实现

1. 创建事件总线
javascript 复制代码
// utils/eventBus.ts
import mitt from 'mitt'
export const eventBus = mitt<{
  showError: string
}>()
2. 请求中发出错误事件
javascript 复制代码
// request.ts
import axios from 'axios'
import { eventBus } from './eventBus'

const request = axios.create()

request.interceptors.response.use(
  res => {
    if (res.data.code !== 0) {
      eventBus.emit('showError', res.data.message || '请求失败')
      return Promise.reject(res.data)
    }
    return res.data
  },
  err => {
    eventBus.emit('showError', err.message || '网络错误')
    return Promise.reject(err)
  }
)
3. UI 层监听事件统一提示
javascript 复制代码
// GlobalErrorListener.tsx
import { useEffect } from 'react'
import { message } from 'antd'
import { eventBus } from './utils/eventBus'

export default function GlobalErrorListener() {
  useEffect(() => {
    const handler = (msg: string) => message.error(msg)
    eventBus.on('showError', handler)
    return () => eventBus.off('showError', handler)
  }, [])

  return null
}
javascript 复制代码
// App.tsx
<GlobalErrorListener />

✅ 优点

  • 完全解耦,适合复杂逻辑(如:错误码分类型处理)
  • 支持全局监听和组件级复用
  • UI 层控制力强

❌ 缺点

  • 逻辑稍复杂,需要维护事件名和事件生命周期
  • 非初学者首选

🧭 最终建议

  • 👉 小项目 / 快速原型:方案一足够
  • 👉 中型项目 / 渐进式解耦:方案二更优雅
  • 👉 大型项目 / 多人协作 / 错误分类复杂:方案三最灵活,最可控

📌 写在最后

请求错误提示并不只是简单的 toast 问题,它关系到 UI 与数据层的架构解耦程度。选对合适的方案,能让你的项目后续更稳定、好维护。

如果你觉得这篇文章对你有帮助,欢迎 👍 点赞 + 收藏,如果你有更好的实践,也欢迎评论区一起交流~

相关推荐
come1123413 分钟前
Vue 响应式数据传递:ref、reactive 与 Provide/Inject 完全指南
前端·javascript·vue.js
musk12121 小时前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
万少2 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL2 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl022 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang2 小时前
前端如何实现电子签名
前端·javascript·html5
今天又在摸鱼2 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿2 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再2 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref
jingling5552 小时前
面试版-前端开发核心知识
开发语言·前端·javascript·vue.js·面试·前端框架