首页 > 语言 > JavaScript > 正文

Node.js 异步异常的处理与domain模块解析

2024-05-06 15:17:21
字体:
来源:转载
供稿:网友

异步异常处理

异步异常的特点

由于node的回调异步特性,无法通过try catch来捕捉所有的异常:

try { process.nextTick(function () {  foo.bar(); });} catch (err) { //can not catch it}

而对于web服务而言,其实是非常希望这样的:

//express风格的路由app.get('/index', function (req, res) { try {  //业务逻辑 } catch (err) {  logger.error(err);  res.statusCode = 500;  return res.json({success: false, message: '服务器异常'}); }});

如果try catch能够捕获所有的异常,这样我们可以在代码出现一些非预期的错误时,能够记录下错误的同时,友好的给调用者返回一个500错误。可惜,try catch无法捕获异步中的异常。所以我们能做的只能是:

app.get('/index', function (req, res) { // 业务逻辑 });process.on('uncaughtException', function (err) { logger.error(err);});

这个时候,虽然我们可以记录下这个错误的日志,且进程也不会异常退出,但是我们是没有办法对发现错误的请求友好返回的,只能够让它超时返回。

domain

在node v0.8+版本的时候,发布了一个模块domain。这个模块做的就是try catch所无法做到的:捕捉异步回调中出现的异常。

于是乎,我们上面那个无奈的例子好像有了解决的方案:

var domain = require('domain');//引入一个domain的中间件,将每一个请求都包裹在一个独立的domain中//domain来处理异常app.use(function (req,res, next) { var d = domain.create(); //监听domain的错误事件 d.on('error', function (err) {  logger.error(err);  res.statusCode = 500;  res.json({sucess:false, messag: '服务器异常'});  d.dispose(); });  d.add(req); d.add(res); d.run(next);});app.get('/index', function (req, res) { //处理业务});

我们通过中间件的形式,引入domain来处理异步中的异常。当然,domain虽然捕捉到了异常,但是还是由于异常而导致的堆栈丢失会导致内存泄漏,所以出现这种情况的时候还是需要重启这个进程的,有兴趣的同学可以去看看domain-middleware这个domain中间件。

诡异的失效

我们的测试一切正常,当正式在生产环境中使用的时候,发现domain突然失效了!它竟然没有捕获到异步中的异常,最终导致进程异常退出。经过一番排查,最后发现是由于引入了redis来存放session导致的。

var http = require('http');var connect = require('connect');var RedisStore = require('connect-redis')(connect);var domainMiddleware = require('domain-middleware');var server = http.createServer();var app = connect();app.use(connect.session({ key: 'key', secret: 'secret', store: new RedisStore(6379, 'localhost')}));//domainMiddleware的使用可以看前面的链接app.use(domainMiddleware({ server: server, killTimeout: 30000}));            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选