wewe-rss RSS订阅管理前端错误监控完整指南:从白屏到分层防御
【免费下载链接】wewe-rss🤗更优雅的微信公众号订阅方式,支持私有化部署、微信公众号RSS生成(基于微信读书)项目地址: https://gitcode.com/GitHub_Trending/we/wewe-rss
打开 wewe-rss(一款微信公众号 RSS 订阅管理工具)的公众号源列表,突然整页白屏;或在账号管理页点击删除,按钮一直转圈直到页面卡死。这类私有化部署场景下,错误现场在用户的浏览器里,服务器日志却一片平静。前端错误监控的价值,就是把"用户说坏了"变成"我知道它哪里坏了"。
🧭 wewe-rss 前端技术栈与目录布局:错误监控从哪些位置入手
wewe-rss 通过微信读书账号订阅微信公众号文章并生成标准 RSS 源,支持私有化部署。它的前端基于 React + TypeScript,Vite 构建,NextUI 组件库,react-router 路由;所有服务端调用走 tRPC + TanStack Query,通知提示统一用 sonner 的 toast。公众号源、账号管理、登录三个页面都在 pages/ 下,全局布局在 layouts/,tRPC 客户端初始化在 provider/ 里。
这个布局之所以重要,是因为错误监控不用另起一套框架,而是"插"在既有结构上:入口文件管全局层,tRPC provider 管网络层,App 根组件管组件层,具体页面管业务层。
为什么前端错误监控要分四层:每层各拦截什么错误
结论先行:不要写一个"全能"的错误处理函数。错误的来源决定了它该在哪一层被接住:
- 全局层:监听 window 的 error 与 unhandledrejection,兜住没人处理过的"漏网之鱼"——脚本异常、没有 catch 的 Promise 拒绝。
- 网络层:tRPC 请求失败。这类错误特征统一(超时、401 过期、5xx),适合集中做重试与提示。
- 组件层:渲染异常,比如访问 undefined 的属性。它发生在 React 渲染流程内部,业务代码根本来不及 catch,只能靠 ErrorBoundary 拦住,否则整页白屏。
- 业务层:有业务语义的失败,例如添加公众号源时链接无效。这种失败是预期内的,用户需要的是引导而不是报错堆栈。
划分的原因:网络错误放到全局层,会丢掉 401 处理与重试策略;渲染错误放到业务层,那层代码根本够不到。把对的错误交给对的层,监控才不会又重又漏。
逐层落地:如何把全局、网络、组件、业务四层监控接入项目
如何全局捕获未处理的 Promise 拒绝
在 main.tsx 渲染之前注册监听。关键不是日志本身,而是带上足够还原现场的信息:
window.addEventListener('unhandledrejection', (event) => { console.error('[wewe-rss] unhandled rejection', { reason: String(event.reason), url: window.location.href, time: new Date().toISOString(), }); event.preventDefault(); // 避免控制台重复打印 });带上 url 和 time,用户反馈"页面坏了"时能直接对上号。以后想改成发送到后端上报接口,只需替换 console.error 这一行。
网络请求错误拦截器怎么做
wewe-rss 的做法不是每个页面挂 hook,而是在 provider/trpc.tsx 的 QueryClient 默认配置里写好 retry 与 onError,一处配置全站生效:
queries: { retry(failureCount, error) { // 401 鉴权失效不重试;其余错误最多重试 3 次 if (isTRPCClientError(error) && error.data?.httpStatus === 401) return false; return failureCount < 3; }, onError(error) { // 401 → "无权限" toast + 清空凭据跳转登录 // 其余 → "请求失败" toast,展示 error.message }, },这样任何 query 和 mutation 都有了统一的网络错误出口,页面代码不用再关心"请求失败怎么办"。
如何防止单个组件崩溃拖垮整个页面
React 的渲染错误捕获只支持 class 组件,所以写一个 ErrorBoundary,包在 App.tsx 的 Routes 外层。出错误时渲染兜底页而不是白屏:
class ErrorBoundary extends React.Component { state = { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } componentDidCatch(error, info) { console.error('[wewe-rss] render error', error, info); } render() { if (this.state.hasError) { return <div>页面渲染出错,<button onClick={() => location.reload()}>点击刷新</button></div>; } return this.props.children; } }componentDidCatch 是组件层错误的收集点,可以在这里记下出错的页面路径,方便上报时定位。
业务层错误提示怎么写才"可操作"
业务错误不必抛给全局层。以 pages/feeds/index.tsx 添加公众号源为例:链接解析失败时服务端返回空,前端直接给出"下一步该做什么"的提示:
const res = await getMpInfo({ wxsLink: link }); if (res[0]) { await addFeed({ id: res[0].id, mpName: res[0].name /* ... */ }); toast.success('添加成功', { description: res[0].name }); } else { // 不暴露原始报错,而是告诉用户下一步动作 toast.error('添加失败', { description: '请检查链接是否正确' }); }原则:业务错误要让用户能"照着做",而不是把堆栈原样怼给他。
前端错误监控常见坑:开发生产差异、上报频率与用户隐私
- 401 是状态不是失败:网络层最易踩的坑是对 401 无脑重试,会话过期时白白刷三次请求。先识别 httpStatus,再决定重试与否。
- 区分开发与生产:用 utils/env.ts 里的环境变量判断。开发环境可以打完整堆栈,生产环境保留 message + URL 即可,避免把技术细节暴露给用户。
- 上报要做频率控制:同一错误(按 message + stack 判断)一分钟内去重,否则一个死循环能把日志和 toast 队列打爆。
- 不上报用户输入内容:链接、验证码属于用户隐私,只记错误信息与页面 URL。
- 私有化用户不会打开控制台:wewe-rss 这类自部署项目最容易忽略的一点——如果错误只进 console.error,等于没有监控。至少要让 toast 可见。
本地动手可以先 git clone https://gitcode.com/GitHub_Trending/we/wewe-rss ,pnpm install 后启动开发环境,逐层验证各监听点的输出。
四层监控先解决的是"错误看得见"。下一步可以把它接上上报端点:服务端加一个错误日志路由做持久化,或接入自托管 Sentry 做按版本聚合——等有数据之后,"哪些错误值得修"就从猜测变成了排序问题。
【免费下载链接】wewe-rss🤗更优雅的微信公众号订阅方式,支持私有化部署、微信公众号RSS生成(基于微信读书)项目地址: https://gitcode.com/GitHub_Trending/we/wewe-rss
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考