解决node项目一个极度困难的捕获异常却无法读取异常信息的问题

本文主要是介绍解决node项目一个极度困难的捕获异常却无法读取异常信息的问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这个项目是集成了第三方NeteaseCloudMusicApi项目的接口代码,我没有直接使用它的接口,因为需要再跑一个npm run开个端口,感觉很麻烦。

所以下定决心,使用拆分代码的方式,硬生生将这个api项目的部分api接口代码集成到了我自己的项目。当然前提是必须能看懂它的代码,然后才能做拆分,否则你根本无从下手

最后终于都搞定了,这个过程很复杂,把它的api代码拆分到了我自己的项目中。

但是有个问题,有时候请求歌曲的时候会报404错误

 但是这个404错误报的明显不正确,因为我已经在代码里打了埋点

 上面证明:这个接口请求实际已经匹配到路由了,所以绝不应该是404错误!

然后排查代码发现这个第三方api的错误处理代码居然写的是404!

这就不对了,肯定起码应该是个500,但是这还不够,起码得知道是什么错误,

所以,把它的msg的值写成捕获到的err

 本以为这样处理就应该能看到具体的异常信息了,但是实际返回结果却还是空对象:

 问题变得棘手了,异常明明捕获到了啊可是为什么打印不出来呢!

看来首先得看看这个err的原始信息是什么? 于是在catch代码块的开头先console.log一下这个err:

然后这个异常信息被打印出来了:

报错如下:

get Err==> TypeError: Cannot read property 'sort' of undefined
    at Object.module.exports [as module] (D:\VueCode\VueProject\myqqmusic\src\registerRouter\NetEaseApi\modules\song_url.js:33:10)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async D:\VueCode\VueProject\myqqmusic\src\registerRouter\NetEaseApi\routes.js:69:40
 

 但是为什么把err赋值给msg就取不到值呢,然后断点调试看了一下这个error的数据结构:

 然后结合GPT分析了一下,按理说: 通过err.message和err.stack应该可以获取到异常的具体信息:

 然后确实看到了异常的具体信息了,这回没有报空值{}:

 

 好了,小结一下:Javascript中Error对象必须通过message或者stack属性来获取到具体信息,

也就是err.message或者err.stack这种形式,不能把Error对象直接赋值给变量!!!否则变量获取的值就是空对象!

但是这种报错信息太难看了,应该根据报错指引,找到异常被触发的地方:

get Err==> TypeError: Cannot read property 'sort' of undefined
    at Object.module.exports [as module] (D:\VueCode\VueProject\myqqmusic\src\registerRouter\NetEaseApi\modules\song_url.js:33:10)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async D:\VueCode\VueProject\myqqmusic\src\registerRouter\NetEaseApi\routes.js:69:40

 根据上面报错信息,找到song_url.js第33行:

这个地方说result没有sort属性,那么result本身极有可能也是个undefined!

所以非常有必要看看它的父级res到底是个什么东西

然后通过断点调试可以看到res底下果然没有data属性,那么result就必然是个undefined了,

难怪result.sort会触发Cannot read property 'sort' of undefined异常了

而且这里可以看到引发异常的真实原因:

// 这个异常信息是放在res.body里面的

 {
  code: -460,
  message: "网络太拥挤,请稍候再试!",
}

 所以在通过res.body.data获取result之前,要先判断一下res.body是否有data这个属性

或者说判断res的返回状态是否正常,因为仅仅根据res.body是否有data属性来判断返回是否正常有点太片面了

然后,我找了一个请求成功的例子:

可以看到请求成功的时候:不仅res.body有data属性,res.body.code还等于200,

所以应该增加以下代码:在res请求失败的时候主动抛出异常,并将res.body作为异常信息:

if (res.body.code != 200 ) {    

    throw new Error(res.body)   // 因为异常的详情信息是存储在res.body里面

  }

但是在前面说的外部异常拦截的地方(catch err代码块),得到结果是:msg没能正确解构出异常的信息,显示的是: [object Object]

 

 

 关于这个问题,我查了很久也查了很多资料,尝试了很多次,都没有能够解决问题。

可以说:这是这次问题排查中难度最大的地方

然后呢,我就尝试着从chatgpt对话,希望能找到答案。

最初按照它给的方法试了好几次,也还是不行。

最后我问了一个关键的神提问:

你没懂我意思,比如原始异常的信息是res.body="{"code":-460,"message":"网络太拥挤,请稍候再试!"}" ,然后我throw new Error(JSON.stringify(res.body)) 抛出了这个异常,我问catch的时候怎么才能把这json格式的异常信息取出来

 然后chatgpt终于给出了正确的回答:

我明白你的问题了。如果你的异常信息是一个JSON字符串,你可以在catch块中使用JSON.parse来解析它,以获取原始的JSON对象。以下是一个示例:

try {const res = { body: '{"code":-460,"message":"网络太拥挤,请稍候再试!"}' };throw new Error(JSON.stringify(res.body));
} catch (error) {try {// 尝试将异常消息解析为JSONconst errorData = JSON.parse(error.message);console.log("Error code:", errorData.code);console.log("Error message:", errorData.message);} catch (parseError) {// 处理解析JSON失败的情况console.error("Error parsing JSON:", parseError);}
}

在这个示例中,我们首先抛出一个异常,异常消息是JSON字符串。然后在catch块中,我们尝试使用JSON.parse将异常消息解析为JSON对象,并访问其中的属性。如果解析失败,我们捕获到解析错误并进行处理。

这样你就可以获取到原始的JSON对象信息了。但要小心处理JSON解析失败的情况,因为异常消息不一定总是有效的JSON字符串。

这里的关键有两点:

1.  自定义异常信息时: new Error构造函数通常接收一个字符串作为错误信息的参数,而不是一个对象

如果是接收参数是对象必须通过JSON.stringify()方法转换成json字符串

2. 当已预知捕获的error是json字符串时,那么此时必须使用JSON.parse()方法把error.message转换成object对象,否则打印出来的就是[object Object]

 所以,代码需要这样修改:

异常主动抛出的部分:

  if (res.body.code != 200 ) {

    // 注意这里new Error的参数不能是对象,而必须是字符串!!!

    // 所以res.body必须通过JSON.stringify转成字符串

    throw new Error(JSON.stringify(res.body))  

  }

 异常捕获的地方:

catch (err) {

                // 因为err.message是JSON字符串,必须通过JSON.parse转换成对象,

               // 否则msg: errData赋值时就会变成: Error: [object Object]

                // 这样msg就获取不到值,变成了空值了

                const errData = JSON.parse(err.message)  //关键点 :必须使用 JSON.parse方法

                console.log("Error message:", errData.message);       

                console.log("get Err==>", err)

                console.log('[ERR]', decode(req.originalUrl), {

                    status: err.status,

                    body: err.body,

                })

                if (!err.body) {

                    res.status(500).send({

                        code: 500,

                        data: null,

                        msg: errData,                    

                    })

                    return

                }

问题解决:前台msg信息终于正常显示出来了,不再是[object Object]

 

 总结:

1. Javascript中的Error对象必须通过message或者stack属性来获取到它的具体信息,

也就是err.message或者err.stack这种形式。

不能把整个Error对象直接赋值给变量!!!否则变量获取的值就是空对象!

2.  自定义异常信息时: new Error构造函数通常接收一个字符串作为错误信息的参数,而不是一个对象

如果是接收参数是对象必须通过JSON.stringify()方法把该对象转换成json字符串

// 主动抛出异常的部分

// 如果是接收参数是对象必须通过JSON.stringify()方法把该对象转换成json字符串

new Error(JSON.stringify(err_obj))

3. 当已预知捕获的error是json字符串时,那么此时必须使用JSON.parse()方法把error.message转换成object对象,否则打印出来的就是[object Object]

// 捕获异常的部分

catch(err) {

// 当已知err是json字符串时,则必须使用JSON.parse()方法把error.message转换成object对象,否则打印出来的就是[object Object]

   errData = JSON.parse(err.message)  // 使用JSON.parse方法是关键

}

这篇关于解决node项目一个极度困难的捕获异常却无法读取异常信息的问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/290416

相关文章

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

qt5cored.dll报错怎么解决? 电脑qt5cored.dll文件丢失修复技巧

《qt5cored.dll报错怎么解决?电脑qt5cored.dll文件丢失修复技巧》在进行软件安装或运行程序时,有时会遇到由于找不到qt5core.dll,无法继续执行代码,这个问题可能是由于该文... 遇到qt5cored.dll文件错误时,可能会导致基于 Qt 开发的应用程序无法正常运行或启动。这种错

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

Java对异常的认识与异常的处理小结

《Java对异常的认识与异常的处理小结》Java程序在运行时可能出现的错误或非正常情况称为异常,下面给大家介绍Java对异常的认识与异常的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参... 目录一、认识异常与异常类型。二、异常的处理三、总结 一、认识异常与异常类型。(1)简单定义-什么是

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。