当前位置:   article > 正文

uncaughtException NodeJS服务总是崩溃的解决办法_nodejs uncaughtexception

nodejs uncaughtexception

有什么问题可以加微信问吧 cannywill ,尽量帮助, 一起进步

许多人都有这样一种映像,NodeJS比较快; 但是因为其是单线程,所以它不稳定,有点不安全,不适合处理复杂业务; 它比较适合对并发要求比较高,而且简单的业务场景。 

Express的作者的TJ Holowaychuk的 告别Node.js一文中列举了以下罪状: 

Farewell NodeJS (TJ Holowaychuk) 

•   you may get duplicate callbacks 
•   you may not get a callback at all (lost in limbo) 
•   you may get out-of-band errors 
•   emitters may get multiple “error” events 
•   missing “error” events sends everything to hell 
•   often unsure what requires “error” handlers 
•   “error” handlers are very verbose 
•   callbacks suck 

其实这几条主要吐嘈了两点: node.js错误处理很扯蛋,node.js的回调也很扯蛋。

 

 

事实上呢?

 


事实上NodeJS里程确实有“脆弱”的一面,单线程的某处产生了“未处理的”异常确实会导致整个Node.JS的崩溃退出,来看个例子, 这里有一个node-error.js的文件: 

 

  1. var http = require('http');
  2. var server = http.createServer(function (req, res) {
  3. //这里有个错误,params 是 undefined
  4. var ok = req.params.ok;
  5. res.writeHead(200, {'Content-Type': 'text/plain'});
  6. res.end('Hello World
  7. ');
  8. });
  9. server.listen(8080, '127.0.0.1');
  10. console.log('Server running at http://127.0.0.1:8080/');


启动服务,并在地址栏测试一下发现 http://127.0.0.1:8080/  不出所料,node崩溃了 


 

  1. $ node node-error
  2. Server running at http://127.0.0.1:8080/
  3. c:githubscript
  4. ode-error.js:5
  5. var ok = req.params.ok;
  6. ^
  7. TypeError: Cannot read property 'ok' of undefined
  8. at Server.<anonymous> (c:githubscript
  9. ode-error.js:5:22)
  10. at Server.EventEmitter.emit (events.js:98:17)
  11. at HTTPParser.parser.onIncoming (http.js:2108:12)
  12. at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:121:23)
  13. at Socket.socket.ondata (http.js:1966:22)
  14. at TCP.onread (net.js:525:27)



 

怎么解决呢?


其实Node.JS发展到今天,如果连这个问题都解决不了,那估计早就没人用了。 

 

使用uncaughtException


我们可以uncaughtException来全局捕获未捕获的Error,同时你还可以将此函数的调用栈打印出来,捕获之后可以有效防止node进程退出,如: 

 

  1. process.on('uncaughtException', function (err) {
  2. //打印出错误
  3. console.log(err);
  4. //打印出错误的调用栈方便调试
  5. console.log(err.stack);
  6. });


这相当于在node进程内部进行守护, 但这种方法很多人都是不提倡的,说明你还不能完全掌控Node.JS的异常。 

 

使用 try/catch


我们还可以在回调前加try/catch,同样确保线程的安全。 

 

  1. var http = require('http');
  2. http.createServer(function(req, res) {
  3. try {
  4. handler(req, res);
  5. } catch(e) {
  6. console.log('
  7. ', e, '
  8. ', e.stack);
  9. try {
  10. res.end(e.stack);
  11. } catch(e) { }
  12. }
  13. }).listen(8080, '127.0.0.1');
  14. console.log('Server running at http://127.0.0.1:8080/');
  15. var handler = function (req, res) {
  16. //Error Popuped
  17. var name = req.params.name;
  18. res.writeHead(200, {'Content-Type': 'text/plain'});
  19. res.end('Hello ' + name);
  20. };


这种方案的好处是,可以将错误和调用栈直接输出到当前发生的网页上。 

 

集成到框架中


标准的HTTP响应处理会经历一系列的Middleware(HttpModule),最终到达Handler,如下图所示: 

\ 


这 些Middleware和Handler在NodeJS中都有一个特点,他们都是回调函数,而回调函数中是唯一会让Node在运行时崩溃的地方。根据这个 特点,我们只需要在框架中集成一处try/catch就可以相对完美地解决异常问题,而且不会影响其它用户的请求request。 

事实上现在的NodeJS WEB框架几乎都是这么做的,如 OurJS开源博客所基于的 WebSvr 

就有这么一处异常处理代码: 

 

  1. Line: 207
  2.   try {
  3.     handler(req, res);
  4.   } catch(err) {
  5.     var errorMsg
  6.       = '
  7.       + 'Error ' + new Date().toISOString() + ' ' + req.url
  8.       + '
  9.       + err.stack || err.message || 'unknow error'
  10.       + '
  11.       ;
  12.     console.error(errorMsg);
  13.     Settings.showError
  14.       ? res.end('<pre>' + errorMsg + '</pre>')
  15.       : res.end();
  16.   }


那么不在回调中产生的错误怎么办?不必担心,其实这样的node程序根本就起不起来。 

此外node自带的 cluster 也有一定的容错能力,它跟nginx的worker很类似,但消耗资源(内存)略大,编程也不是很方便,OurJS并没有采用此种设计。 

 

守护NodeJS进程和记录错误日志


现 在已经基本上解决了Node.JS因异常而崩溃的问题,不过任何平台都不是100%可靠的,还有一些错误是从Node底层抛出的,有些异常 try/catch和uncaughtException都无法捕获。之前在运行ourjs的时侯,会偶尔碰到底层抛出的文件流读取异常,这就是一个底层 libuv的BUG,node.js在0.10.21中进行了修复。 

面对这种情况,我们就应该为nodejs应用添加守护进程,让NodeJS遭遇异常崩溃以后能马上复活。 

另外,还应该把这些产生的异常记录到日志中,并让异常永远不再发生。 

 

使用node来守护node


node-forever 提供了守护的功能和LOG日志记录功能。 

安装非常容易 

 

[sudo] npm install forever


使用也很简单 

 

  1. $ forever start simple-server.js
  2. $ forever list
  3.   [0] simple-server.js [ 24597, 24596 ]


还可以看日志 

 

forever -o out.log -e err.log my-script.js


https://blog.csdn.net/xiunai78/article/details/40378965/

使用shell启动脚本守护node


使用node来守护的话资源开销可能会有点大,而且也会略显复杂,OurJS直接在开机启动脚本来进程线程守护。 

如在debian中放置的 ourjs 开机启动文件: /etc/init.d/ourjs 

这个文件非常简单,只有启动的选项,守护的核心功能是由一个无限循环 while true; 来实现的,为了防止过于密集的错误阻塞进程,每次错误后间隔1秒重启服务 

 

  1. WEB_DIR='/var/www/ourjs'
  2. WEB_APP='svr/ourjs.js'
  3. #location of node you want to use
  4. NODE_EXE=/root/local/bin/node
  5. while true; do
  6.     {
  7.         $NODE_EXE $WEB_DIR/$WEB_APP config.magazine.js
  8.         echo "Stopped unexpected, restarting
  9. "
  10.     } 2>> $WEB_DIR/error.log
  11.     sleep 1
  12. done
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/230763
推荐阅读
相关标签
  

闽ICP备14008679号