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

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

相关推荐
GinoWi23 分钟前
HTML基本格式 - 第一个HTML网页
前端
顶鲜花的牛粪26 分钟前
Astro 项目升级全栈:EdgeOne Pages 部署指南
前端
0***R51537 分钟前
前端云原生
前端·云原生
月弦笙音1 小时前
【Promise.withResolvers】发现这个api还挺有用
前端·javascript·typescript
疯狂踩坑人1 小时前
MCP理论和实战,然后做个MCP脚手架吧
前端·node.js·mcp
中杯可乐多加冰1 小时前
基于 DeepSeek + MateChat 的证券智能投顾技术实践:打造金融领域的专属大Q模型助手
前端·人工智能
凡人程序员1 小时前
搭建简易版monorepo + turborepo
前端·javascript
丸子哥哥1 小时前
同一个域名,如何添加多个网站?
服务器·前端·nginx·微服务
不努力也不会混1 小时前
vite联邦实现微前端(vite-plugin-federation)
前端·vue.js
伍亿伍千万1 小时前
Uptime Kuma修改作为内嵌页面的自适应
前端