将req和res显式添加到域不会传播错误来表示中间件

我在快递节点上玩弄域名和群集,并进入这种情况。 我有一个产生每个核心工作者的集群,对于每个工作人员,我创build一个使用每个请求域策略来处理错误的快速服务器。

下面给出的解决scheme可以正常工作,但是当显式地将请求和响应对象添加到域时,错误中间件将停止被调用。 我不知道为什么会引入这种行为。

问题:

  1. 为什么发生?
  2. 我是否以正确的方式使用域名?
  3. 我可以通过“process.domain”访问工作者当前的域吗?还是我需要做一些不同的事情?

提前致谢!

我的app.js:

var express = require('express') , http = require('http') , path = require('path') , domain = require('domain') , cluster = require('cluster') , http = require('http') , numCPUs = require('os').cpus().length; if (cluster.isMaster) { // fork workers for (var i = 0; i < numCPUs; i++) { cluster.fork(); } // when a worker dies create a new one cluster.on('exit', function(worker, code, signal) { cluster.fork(); }); } else { var app = express(); //domains app.use(function domainMiddleware(req, res, next) { var reqDomain = domain.create(); res.on('close', function () { reqDomain.dispose(); }); res.on('finish', function () { reqDomain.dispose(); }); reqDomain.on('error', function (err) { reqDomain.dispose(); // delegate to express error-middleware next(err); }); // Adding the request and response objects to the domain // makes the express error-middleware to not being called. // reqDomain.add(req); // reqDomain.add(res); reqDomain.run(next); }); // all environments app.set('port', process.env.PORT || 3000); app.set('views', __dirname + '/views'); app.set('view engine', 'jade'); app.use(express.favicon()); //app.use(express.logger('dev')); app.use(express.bodyParser()); app.use(express.methodOverride()); app.use(app.router); app.use(express.static(path.join(__dirname, 'public'))); // for testing which cluster that serves the request app.get('/', function(req, res, next) { res.json(200, { id: cluster.worker.id }); }); app.get('/error', function(req, res, next) { var fs = require('fs'); // intentionally force an error fs.readFile('', process.domain.intercept(function(data) { // when using intercept we dont need this line anymore //if (err) throw err; res.send(data); })); }); app.use(function(err, req, res, next) { console.log('ERROR MIDDLEWARE', err); res.writeHeader(500, {'Content-Type' : "text/html"}); res.write("<h1>" + err.name + "</h1>"); res.end("<p>" + err.message + "</p>"); }); http.createServer(app).listen(app.get('port'), function(){ console.log('Express server listening on port ' + app.get('port')); }); } 

这是由于对reqDomain.dispose()的调用。 从dispose文档 :

dispose方法销毁一个域,并尽最大努力清理与该域相关的任何和所有IO。 stream被中止,结束,closures和/或销毁。 定时器被清除。 显式绑定的callback不再被调用。 任何因此而引发的错误事件都将被忽略。

一旦reqres被添加到域,处置域结束/closures/销毁它们 。 你可以通过在reqDomain.on('error')callback中显式地发送一些输出到res来testing这个,但是在处理这个域之前。

简单地把呼叫移到next行似乎解决了这个问题:

 reqDomain.on('error', function (err) { next(err); reqDomain.dispose(); }); 

至于process.domain ,我以前没有见过,真的很惊讶,它的工作。 我查看了源代码, 发现如下 :

 Domain.prototype.enter = function() { if (this._disposed) return; // note that this might be a no-op, but we still need // to push it onto the stack so that we can pop it later. exports.active = process.domain = this; stack.push(this); }; 

所以,看起来process.domain总是“最新”的域名。 就我个人而言,我可能会附加到req对象或域的东西,所以你可以更清楚地知道哪个域应该处理错误(虽然在实践中,它可能是process.domain永远是你正在寻找的域)。