如何创建将每个请求包装在自己的域中的 Express/Connect 中间件?
5 回答
更新:下面描述的方法已在连接域NodeJS 模块中实现,可用于 Connect 或 Express 应用程序。
从 Express 3 开始,express.createServer
已弃用,其回调应转换为中间件。在中间件中,将请求和结果对象添加到请求域中很重要,以便它们触发的错误由域错误处理程序处理。
我的中间件看起来像这样:
var domain = require('domain');
app.use(function(req, res, next) {
var requestDomain = domain.create();
requestDomain.add(req);
requestDomain.add(res);
requestDomain.on('error', next);
requestDomain.run(next);
});
如果您http.createServer
从顶级域中调用,则可以避免将请求和响应添加到请求域,但域文档似乎表明按请求域是最佳实践。
请注意,上面的代码不会执行任何域清理操作,例如强制释放请求域。我的中间件选择再次通过中间件堆栈传递错误,以便稍后由特定的错误处理中间件处理。YMMV。
Speaker Deck 上的这组幻灯片提供了简洁的概述:
幻灯片中的 Express 中间件代码:
var createDomain = require('domain').create;
app.use(function(req, res, next) {
var domain = createDomain();
domain.on('error', function(err) {
// alternative: next(err)
res.statusCode = 500;
res.end(err.message + '\n');
domain.dispose();
});
domain.enter();
next();
});
我很幸运能更换库存
var app = express.createServer();
和:
var domainCreate = require('domain').create;
var app = express.createServer(function (req, res, next) {
var domain = domainCreate();
domain.run(next);
});
然后在您的中间件中,您可以将属性添加到 process.domain 或添加额外的错误处理。
这是一个较晚的答案,但请查看express-domain-moddleware模块。它会自动为每个请求创建一个新域。活动域可以由您的路由中的 process.domain 引用。这是一个例子:
//with domain-middleware
app.use(require('express-domain-middleware'));
app.use(app.router);
app.use(function errorHandler(err, req, res, next) {
console.log('error on request %d %s %s: %j', process.domain.id, req.method, req.url, err);
res.send(500, "Something bad happened. :(");
if(err.domain) {
//you should think about gracefully stopping & respawning your server
//since an unhandled error might put your application into an unknown state
}
});
app.get('/error', function(req, res, next) {
db.query('SELECT happiness()', process.domain.intercept(function(rows) {
fs.readFile('asldkfjasdf', process.domain.intercept(function(contents) {
process.nextTick(process.domain.intercept(function() {
throw new Error("The individual request will be passed to the express error handler, and your application will keep running.");
}));
}));
}));
});
这些域目前在节点中已弃用:
https://nodejs.org/api/domain.html
出于“分区错误”的目的,我创建了一个库,它允许您以一种很好的方式编写异步代码:https ://github.com/vacuumlabs/yacol 。它的好处之一是您可以拥有具有非常好的语义的类似域的行为;一探究竟!