许多人都有这样一种映像,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的文件:

var http = require('http');
var server = http.createServer(function (req, res) {
//这里有个错误,params 是 undefined
var ok = req.params.ok;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
});
server.listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');

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

$ node node-error
Server running at http://127.0.0.1:8080/
c:\github\script\node-error.js:5
var ok = req.params.ok;
^
TypeError: Cannot read property 'ok' of undefined
at Server.<anonymous> (c:\github\script\node-error.js:5:22)
at Server.EventEmitter.emit (events.js:98:17)
at HTTPParser.parser.onIncoming (http.js:2108:12)
at HTTPParser.parserOnHeadersComplete [as onHeadersComplete] (http.js:121:23)
at Socket.socket.ondata (http.js:1966:22)
at TCP.onread (net.js:525:27)

怎么解决呢?

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

使用uncaughtException

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

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

  

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

使用 try/catch

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

var http = require('http');
http.createServer(function(req, res) {
try {
handler(req, res);
} catch(e) {
console.log('\r\n', e, '\r\n', e.stack);
try {
res.end(e.stack);
} catch(e) { }
}
}).listen(8080, '127.0.0.1');
console.log('Server running at http://127.0.0.1:8080/');
var handler = function (req, res) {
//Error Popuped
var name = req.params.name;
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello ' + name);
};

  

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

集成到框架中

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

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

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

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

try {
handler(req, res);
} catch(err) {
var errorMsg
= '\n'
+ 'Error ' + new Date().toISOString() + ' ' + req.url
+ '\n'
+ err.stack || err.message || 'unknow error'
+ '\n'
;
console.error(errorMsg);
Settings.showError
? res.end('<pre>' + errorMsg + '</pre>')
: res.end();
}

那么不在回调中产生的错误怎么办?不必担心,其实这样的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

使用也很简单

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

还可以看日志

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

使用shell启动脚本守护node

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

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

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

WEB_DIR='/var/www/ourjs'
WEB_APP='svr/ourjs.js'
#location of node you want to use
NODE_EXE=/root/local/bin/node
while true; do
{
$NODE_EXE $WEB_DIR/$WEB_APP config.magazine.js
echo "Stopped unexpected, restarting \r\n\r\n"
} 2>> $WEB_DIR/error.log
sleep 1
done

错误日志记录也非常简单,直接将此进程控制台当中的错误输出到error.log文件即可: 2>> $WEB_DIR/error.log  这一行, 2 代表 Error。

Node出错导致运行崩溃的解决方案相关推荐

  1. node mysql崩溃_Node出错导致运行崩溃的解决方案

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

  2. Openwrt 18.06 iPhone XR usb tethering导致内核崩溃问题解决方案

    环境描述: openwrt 18.06  (Linux-4.9.120) 问题描述: iPhone XR usb tethering出现内核崩溃 root@GL-MIFI:/# [  253.1302 ...

  3. PyQt5随笔:PyQt5 程序在开机自启动时读取文件出错导致崩溃解决办法

    PyQt5随笔:PyQt5 程序在开机自启动时读取文件出错导致崩溃解决办法 1.前言 最近在写一个 Python+pyqt5 小项目,在改善过程中想添加一个日志记录,我是打算用txt 文件记录就好,操 ...

  4. activex html 崩溃_网站导致浏览器崩溃的原因总结(多款浏览器)

    面试某公司的时候,面试官问到,导致浏览器崩溃的原因有哪些?愚辈不才,仅回答出了内存泄漏.其实在网页在装载的过程中,常常由于种种原因使浏览器的反映变的很慢,或造成浏览器失去响应,甚至会导致机器无法进行其 ...

  5. 速修复!OpenSSL 披露DoS 和证书验证高危漏洞,可导致服务器崩溃

     聚焦源代码安全,网罗国内外最新资讯! 编译:奇安信代码卫士团队 刚刚,OpenSSL 项目发布安全公告指出,OpenSSL 产品中存在两个漏洞(CVE-2021-3449和CVE-2021-3450 ...

  6. 10个方法教你解决虚幻4运行崩溃问题

    "多年来我一直在我的电脑上使用不同版本的虚幻引擎 4,但最近它突然在启动时崩溃.我最初认为这是一个项目相关的问题,但后来注意到即使是从桌面图标或 Epic Games Launcher执行U ...

  7. 插件加载导致outlook崩溃

    问描述: 加载插件导致outlook崩溃(向outlook2016拖入文件,之间显示) 由于对插件的编程几乎不理解就有了上文,然后不知道为啥,心里一个尽的想着,让插件自己重启就ok了,看看插件哪里出错 ...

  8. Solidworks出错导致solidworks意外退出 故障模 vcruntime140

    在 Solidworks 启动到 SOLIDWORKS PDM 时弹出窗口崩溃,显示出错,导致solidworks意外退出 故障模 vcruntime140:000064c0,尝试在 SOLIDWOR ...

  9. 【解决】MySql 5.6 运行崩溃错误

    [解决]MySql 5.6 运行崩溃错误 最近弄了一台云主机,配置是20G磁盘空间,1G运行内存的Linux服务器.在上面安装了LAMP(RHEL7.2+Apache2.4+MySql5.6+PHP5 ...

最新文章

  1. 三维可视化模块发布了
  2. PowerDesigner逆向工程mysql
  3. Android系统中的进程管理:进程的优先级
  4. SQL Server 审计
  5. 全网最详细的docker配置nginx http2 优化高速访问
  6. 影响力-你为什么说是
  7. 自动驾驶模拟器Carla之python编程-(1)简介
  8. 理解矩阵,矩阵背后的现实意义 [转]
  9. 【Java从0到架构师】个人简历项目实战
  10. php模拟input 的file上传文件
  11. 查询视图遇见的问题,以及访问另一个数据库的表
  12. 关于分卷压缩文件打不开的问题
  13. 电脑自带蓝牙与HC-06蓝牙模块使用串口助手通信
  14. 基于JAVA的GUI编程的的迷宫游戏 2020-12-15
  15. 删除windows默认共享
  16. 08年度的佳作——《真・恋姫†無双》玩后感(蜀国篇)+AGTH真正提取大法
  17. WMS仓储管理系统定制
  18. 关于CLASS , SEL, IMP的说明
  19. 莫比乌斯反演小结 + 黑暗爆炸 2301
  20. 旅游景区|“沉浸式夜游”如何玩?深圳光语数字

热门文章

  1. oracle迁移父子数据
  2. UVA - 10340 ​​​​​​​All in All
  3. hosts文件不起作用
  4. oracle下载(转载)
  5. 2月第3周国内域名商TOP10:爱名网排名升至第八
  6. 100c之23:两个平方数
  7. Qt4小技巧——QTextEdit自动滚屏
  8. 方便微信公众号等手机网页调试插件eruda和vConsole
  9. 启动spark shell
  10. Oracle Minus关键字 不包含 取差集