React Native异常疑问:FetchTool自定义错误未被AccessService捕获
问题:React Native中catch块无法捕获自定义错误,反而得到“幽灵错误”
环境配置
- React Native 运行在 Android 虚拟设备(API 23)
- Android Gradle 插件版本:7.2.0
- Gradle 版本:7.4.2
build.gradle关键配置片段:
buildscript { ext { kotlinVersion = "1.5.0" RNNKotlinVersion = kotlinVersion buildToolsVersion = "31.0.0" minSdkVersion = 23 compileSdkVersion = 31 targetSdkVersion = 28 ... }
问题场景
向本地服务器地址 http://10.0.2.2:8888/myapp/auth 发起登录验证POST请求,服务器返回500响应码(表示邮箱/密码错误)。
FetchTool 中针对500场景抛出了自定义错误 new Error(JSON.stringify(responseObject)),但调用它的 AccessService 的catch块捕获到的却是如下“幽灵错误”:
LOG ERROR..:{"line":25722,"column":33,"sourceURL":"http://10.0.2.2:8081/index.bundle?platform=android&dev=true&minify=false&app=com.myapp&modulesOnly=false&runModule=true"}
相关代码
AccessService 代码
export default class AccessService { static confirmLogon(email, password) { const login = { email: email, password: password }; const headers = { 'Content-Type': 'application/json', } const uri = properties.appurl + '/auth'; return FetchTool.post(uri, headers, login) .then(credentials => { return credentials; }) .catch(error => { // 此处捕获到幽灵错误 console.log('ERROR..:' + JSON.stringify(error)) throw error; }); } }
FetchTool 代码
export default class FetchTool { static post(uri, headers, playload) { return this.executeRequest(uri, headers, playload, 'POST'); } static executeRequest(uri, headers, playload, method) { if (headers['Content-Type'] && headers['Content-Type'] == 'application/json') { playload = JSON.stringify(playload); } const requestInfo = { method: method, body: playload, headers: headers } // uri = http://10.0.2.2:8888/myapp/auth return fetch(uri, requestInfo) .then(response => { if (response.ok) { // 正常返回JSON的逻辑 } else { return response.text() .then(responseText => JSON.parse(responseText)) .then(responseObject => { if(responseObject.statusCode === 500) { // 错误触发点 throw new Error(JSON.stringify(responseObject)); } else { // 其他错误处理逻辑 } }) } }) } }
原因分析
- Promise链错误传递断层:
FetchTool中response.text().then().then()的子Promise链里抛出的错误,没有被正确向上传递到外层Promise。React Native调试环境遇到未被显式捕获的Promise错误时,会输出包含bundle位置的“幽灵错误”,而非自定义错误内容。 - Error对象序列化丢失信息:直接用
JSON.stringify(error)序列化原生Error对象时,只会输出其内部的位置属性(line、column等),自定义的message等关键信息会被忽略,导致日志里看不到错误详情。
解决方案
方案1:修复Promise链的错误传递
在FetchTool的错误处理子链末尾添加catch,确保错误能向上传递到AccessService的catch块:
return fetch(uri, requestInfo) .then(response => { if (response.ok) { // 正常返回JSON的逻辑 } else { return response.text() .then(responseText => { try { return JSON.parse(responseText); } catch (parseError) { throw new Error('响应解析失败'); } }) .then(responseObject => { if(responseObject.statusCode === 500) { throw new Error(JSON.stringify(responseObject)); } else { // 其他错误处理逻辑 } }) // 显式捕获子链错误并向上抛出 .catch(fetchError => { throw fetchError; }); } })
方案2:正确读取Error对象的信息
在AccessService的catch块中,不要直接序列化Error对象,而是读取其message属性:
.catch(error => { console.log('ERROR..:' + error.message); throw error; });
方案3:使用自定义错误类(可选)
创建自定义错误类携带业务信息,避免原生Error的序列化限制:
// 定义自定义错误类 class ApiError extends Error { constructor(message, statusCode) { super(message); this.statusCode = statusCode; this.name = 'ApiError'; } } // 在FetchTool中抛出自定义错误 throw new ApiError('邮箱/密码错误', 500); // 在AccessService中捕获并打印 .catch(error => { console.log(`ERROR..: ${error.name} - ${error.message} (状态码: ${error.statusCode})`); throw error; });
内容的提问来源于stack exchange,提问作者araraujo
相关产品推荐
相关产品推荐

