关于请求封装中关于错误提示的三种实践方案: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 与数据层的架构解耦程度。选对合适的方案,能让你的项目后续更稳定、好维护。

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

相关推荐
誰能久伴不乏16 分钟前
Linux如何执行系统调用及高效执行系统调用:深入浅出的解析
java·服务器·前端
涔溪1 小时前
响应式前端设计:CSS 自适应布局与字体大小的最佳实践
前端·css
今禾1 小时前
前端开发中的Mock技术:深入理解vite-plugin-mock
前端·react.js·vite
你这个年龄怎么睡得着的1 小时前
Babel AST 魔法:Vite 插件如何让你的 try...catch 不再“裸奔”?
前端·javascript·vite
我想说一句2 小时前
掘金移动端React开发实践:从布局到样式优化的完整指南
前端·react.js·前端框架
jqq6662 小时前
Vue3脚手架实现(九、渲染typescript配置)
前端
码间舞2 小时前
Zustand 与 useSyncExternalStore:现代 React 状态管理的极简之道
前端·react.js
Dream耀2 小时前
提升React移动端开发效率:Vant组件库
前端·javascript·前端框架
冰菓Neko2 小时前
HTML 常用标签速查表
前端·html
gis收藏家2 小时前
从稀疏数据(CSV)创建非常大的 GeoTIFF(和 WMS)
前端