uni-app如何实现App端内的全局异常捕获 uni-app错误日志上传系统【实战】

作者:袖梨 2026-08-08

uni-app如何实现App端内的全局异常捕获 uni-app错误日志上传系统【实战】需要先看清适用场景和关键步骤,避免只记结论却忽略实际限制。

App端需用uni.onError和uni.onUnhandledRejection捕获JS异常,二者须在App.vue的onLaunch中注册;原生崩溃需接入UMeng、Bugly等SDK,通过插件市场引入原生插件;上报日志须结构化携带上下文,加锁防死循环,并脱敏敏感信息。

App端如何捕获未处理的JavaScript异常

uni-app在App端(iOS/Android)无法直接用window.onerrorPromise.catch兜住所有错误,因为原生容器运行环境与Web不同。真正有效的入口是uni.onErroruni.onUnhandledRejection,它们由uni-app框架在App端主动桥接了原生异常通道。

注意:这两个API必须在App.vueonLaunch中注册,延迟注册(比如放到某个页面里)会漏掉冷启动阶段的异常。

  1. uni.onError能捕获同步执行错误、throw语句、生命周期钩子内抛出的异常
  2. uni.onUnhandledRejection捕获未被catch的Promise拒绝(包括async/await中未try的reject)
  3. 不捕获Vue组件渲染错误(如模板语法错、响应式数据访问undefined),这类需配合config.errorHandler(仅H5/小程序生效,App端无效)

为什么uni-app的App端需要额外处理原生层崩溃

JS层异常只是冰山一角。App端真正致命的是原生崩溃(如iOS EXC_BAD_ACCESS、Android NullPointerException),这些完全绕过JS事件系统,uni.onError根本收不到。

解决方案是接入原生SDK:iOS用UMeng+ crashFirebase Crashlytics,Android用buglyfirebase-crashlytics-ndk。uni-app本身不提供原生崩溃采集能力,必须通过uni-app插件市场引入已封装好的原生插件(如uni-crash-report),或自己写原生模块桥接。

  1. 纯JS异常上报不能替代原生崩溃监控,二者必须共存
  2. 原生插件需在manifest.json → App模块配置中勾选对应SDK,否则打包后无效果
  3. 调试阶段原生崩溃日志只出现在Xcode/Android Studio的Logcat里,不会自动上报

错误日志怎么结构化上传才便于排查

直接把err.messageerr.stack发上去意义有限。真实线上问题往往依赖上下文:用户当前页面、vuex状态、网络类型、设备型号、uni-app版本、是否登录等。

推荐在上报前拼装一个最小但完整的上下文对象,例如:

{  "timestamp": Date.now(),  "page": getCurrentPages()[0]?.$route?.path || "",  "platform": uni.getSystemInfoSync().platform,  "appVersion": uni.getSystemInfoSync().version,  "uniVersion": uni.getSystemInfoSync().uniCompileVersion,  "userInfo": uni.getStorageSync('userInfo') || null,  "networkType": uni.getNetworkTypeSync?.() || "unknown",  "error": {    "message": err.message,    "stack": err.stack,    "type": "js_error" // 或 "promise_reject"  }}
  1. 避免在uni.onError回调里调用异步API(如uni.getStorage),可能触发竞态或失败;应提前缓存关键字段
  2. stack字符串过长(尤其带source map时)可能超HTTP请求体限制,建议截断到2000字符以内
  3. 敏感字段(如token、手机号)必须脱敏后再上传,严禁明文

如何防止错误上报本身失败导致死循环

上报接口挂了、网络超时、JSON序列化失败……这些都可能触发新的错误,进而再次进入uni.onError,形成上报风暴。

  1. 给上报逻辑加单次执行锁:if (uploading) return; uploading = true;,成功或超时后重置
  2. 使用uni.request时设置timeout: 3000,并始终监听fail回调,失败时不重试
  3. 禁用console.error等副作用操作——它们在某些低端Android机上可能引发额外异常
  4. 上线前务必在弱网模拟器(如Android Emulator的Network Speed设为GPRS)下验证上报链路是否静默失败

最麻烦的不是捕获不到错误,而是捕获到了却传不上去,或者传上去的日志缺关键字段。设备信息、页面路径、堆栈这三项,少一个就大概率要多花两小时翻日志找线索。

相关文章

精彩推荐