本文以连接错误ECONNREFUSED为例,看看nodejs对错误处理的过程。 假设我们有以下代码
?
1 2 |
|
如果本机上没有监听9999端口,那么我们会得到以下输出。
?
1 2 3 4 5 6 7 8 9 10 |
|
我们简单看一下connect的调用流程。
?
1 2 3 4 5 6 7 8 |
|
接着我们看一下C++层connect的逻辑
?
1 2 3 4 |
|
C++层直接调用Libuv的uv_tcp_connect,并且设置回调是AfterConnect。接着我们看libuv的实现。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
我们看到Libuv以异步的方式调用操作系统,然后把request挂载到handle中,并且注册等待可写事件,当连接失败的时候,就会执行uv stream_io回调,我们看一下Libuv的处理(uv stream_io)。
?
1 2 3 4 5 6 7 8 |
|
获取错误信息后回调C++层的AfterConnect。
?
1 2 3 4 5 6 7 8 9 |
|
接着调用JS层的oncomplete回调。
?
1 2 3 4 5 6 7 8 9 10 11 |
|
exceptionWithHostPort构造错误信息,然后销毁socket并且以ex为参数触发error事件。我们看看uvExceptionWithHostPort的实现。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
我们看到错误信息主要通过uvErrmapGet获取
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
继续往下看,uvErrmapGet调用了C++层的uv模块的getErrorMap。
?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
|
我们看到错误信息存在per_process::uv_errors_map中,我们看一下uv_errors_map的定义。
?
1 2 3 4 5 6 7 8 9 10 11 |
|
UV_ERRNO_MAP宏展开后如下
?
1 2 3 4 |
|
所以导出到JS层的结果如下
?
1 2 3 4 5 6 |
|
Node.js最后会组装这些信息返回给调用方。这就是我们输出的错误信息。那么为什么会是ECONNREFUSED呢?我们看一下操作系统对于该错误码的逻辑。
?
1 2 3 4 5 6 7 8 9 10 |
|
当操作系统收到一个发给该socket的rst包的时候会执行tcp_reset,我们看到当socket处于发送syn包等待ack的时候,如果收到一个fin包,则会设置错误码为ECONNREFUSED。我们输出的正是这个错误码。
总结
到此这篇关于nodejs的错误处理过程记录的文章就介绍到这了,更多相关nodejs错误处理内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://zhuanlan.zhihu.com/p/364638398
本文链接:https://my.lmcjl.com/post/7530.html
4 评论