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

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

相关推荐
惊鸿一博21 分钟前
图标加载方式_zeroIcon_是否加前缀mdi
开发语言·前端·javascript
2501_9400417435 分钟前
前端工程化进阶:5个高交互与可视化项目提示词
前端
你很易烊千玺35 分钟前
JS 异步 从零讲(大白话 + 真实场景 + 可运行案例)
前端·javascript·vue.js
why技术3 小时前
AI Coding开始进入第四个时代,我还没上车呢!
前端·人工智能·后端
大家的林语冰3 小时前
CSS 已死?DOM 性能黑洞!Pretext 排版革命让你在文本间跳舞,没有 DOM 也能纵享丝滑~
前端·javascript·css
vipbic4 小时前
我也该升级了,陪伴了我7年的博客
前端
Lee川4 小时前
RAG 实战:从一篇掘金文章出发,拆解检索增强生成的全链路
前端·人工智能·后端
Lee川4 小时前
MCP 高德地图实战:当 AI 学会使用工具,一个协议如何重塑大模型的行动边界
前端·人工智能·后端
ZC跨境爬虫4 小时前
跟着 MDN 学CSS day_14:(尺寸调整技能测试与实战解析)
前端·css·ui·html·tensorflow
kyriewen4 小时前
用魔法打败魔法:我让AI替我去面试前端岗,AI面试官给我打了92分,还发了offer
前端·javascript·面试