app端异常捕获必须用uni.onerror和uni.onunhandledrejection,且需在app.vue的onlaunch中注册;js异常捕获仅报错不恢复,自动重试需分h5端chunkloaderror监听等两层实现。

App端必须用 uni.onError 和 uni.onUnhandledRejection
Web端能靠 window.onerror 和 unhandledrejection 捕获大部分异常,但 App(iOS/Android)原生容器不走这套机制,window.onerror 在 App 里基本无效。真正起作用的是 uni-app 框架桥接的两个 API:uni.onError 捕同步错误(如生命周期钩子里 throw、uni.setStorageSync 参数非法),uni.onUnhandledRejection 捕未 catch 的 Promise 拒绝(包括 async/await 中漏掉的 try)。这两个必须在 App.vue 的 onLaunch 里注册,晚了就收不到冷启动阶段的异常。
常见错误:把它们写在某个页面的 onLoad 里,结果 App 启动时 JS 报错直接静默失败,用户看到白屏却无日志可查。
自动重试不能只靠 JS 异常捕获
JS 层异常捕获(比如 uni.onError)只能告诉你“哪里错了”,但没法自动恢复——它不等价于网络请求失败或 chunk 加载失败这类可重试场景。真正的自动重试要分两层:
- H5 端:靠 index.html 里注入的脚本监听
ChunkLoadError、Unexpected token ' 等资源加载失败,触发 <code>location.reload()(参考你知识库里的那段自执行脚本) - App 端:没有 HTML reload 机制,也不能简单刷新整个 WebView(体验差、状态丢失)。可行做法是拦截特定业务错误(如
uni.request返回 503 或超时),在请求封装层做有限次数重试(建议 ≤2 次),并配合 loading 锁防重复提交
别试图在 uni.onError 里写 uni.reLaunch ——它会破坏路由栈,且无法区分是代码 bug 还是临时网络抖动。
上报日志必须带上下文,否则等于没报
只传 err.message 和 err.stack 上去,线上排查时基本 useless。真实问题定位依赖这些字段:
-
pagePath:当前页面路径(用getCurrentPages()取) -
networkType:uni.getNetworkType结果,区分 Wi-Fi/4G/无网络 -
platform:uni.getSystemInfoSync().platform,iOS 还是 Android -
uniVersion:uni.getSystemInfoSync().uniVersion -
vuexStateSnapshot:关键模块状态(如登录态、当前 tab),但需脱敏(过滤 token、手机号)
注意:App 端 uni.getSystemInfoSync() 在某些低版本可能返回空,建议加 try-catch 包裹;上报前用 JSON.stringify 序列化时也要防循环引用,否则直接卡死。
原生崩溃完全绕过 JS 层,必须单独接入 SDK
uni.onError 收不到 iOS EXC_BAD_ACCESS 或 Android NullPointerException,这类崩溃发生在 JS 引擎之外。解决方案只有两个:
- 从插件市场引入已封装的原生插件,如
uni-crash-report(集成 Bugly iOS/Android SDK) - 自己写原生模块桥接 Firebase Crashlytics 或 UMeng Crash
关键点:必须在 manifest.json → App 模块配置 中勾选对应 SDK,否则打包后插件不生效;调试阶段崩溃日志只出现在 Xcode Console 或 Android Studio Logcat,不会自动上报,得真机连调试器看。
JS 异常和原生崩溃日志必须共存,缺一不可——前者帮你修逻辑,后者帮你保上线稳定性。











