【发布时间】:2016-09-09 12:31:55
【问题描述】:
我的中间件布局大概是这样的:
let express = require('express');
let app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(myBigMiddleware); // this will call 3rd party service and can time-out
app.use(myAfterwardsMiddleware);
[maybe more post-processing middleware]
我想要实现的是任何在 XX 秒内没有得到响应的请求都应该被取消 + 一些 HTTP 错误应该被发送到浏览器/客户端。
我发现https://github.com/expressjs/timeout 似乎可以做到这一点,但不知何故我太笨了,无法使用它。我不明白如何取消中间件管道,而是执行res.status(503).end(); 之类的操作。
调整以上内容:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(timeout(5000));
app.use(haltOnTimedout);
function haltOnTimedout(req, res, next){
if (!req.timedout) next();
else console.log('REQUEST TIMEOUT');
}
app.use(myBigMiddleware); // this will call 3rd party service and can time-out
app.use(myAfterwardsMiddleware);
[maybe more post-processing middleware]
会给我以下输出:
events.js:176
domain.enter();
^
TypeError: domain.enter is not a function
at IncomingMessage.emit (events.js:176:12)
at Timeout._onTimeout (/home/user/dev/node_modules/connect- timeout/index.js:43:11)
at tryOnTimeout (timers.js:232:11)
at Timer.listOnTimeout (timers.js:202:5)
*app died*
当我将app.use(haltOnTimedout); 放在中间件链的最末端时,我会得到相同的结果。
我做错了什么?或者我应该在哪里/如何插入超时中间件以捕获超时并发送我的 HTTP 响应,取消所有后续中间件? :/
[编辑] 我发现app.use(myBigMiddleware); 可能会导致这种情况,因为当我用普通的app.use(()=>{}); 替换它时,我会在控制台和浏览器中得到以下信息(应用仍在运行):
ServiceUnavailableError: Response timeout
at IncomingMessage.<anonymous> (/home/user/dev/node_modules/connect-timeout/index.js:70:8)
at emitOne (events.js:96:13)
at IncomingMessage.emit (events.js:188:7)
at Timeout._onTimeout (/home/user/dev/node_modules/connect-timeout/index.js:43:11)
at tryOnTimeout (timers.js:224:11)
at Timer.listOnTimeout (timers.js:198:5)
这有点接近我的需要,实际上我现在可以将以下中间件添加到堆栈的末尾以实现我想要的:
app.use(function(err, req, res, next) {
if (req.timedout) {
res.status(503).end();
} else {
res.status(err.status || 500).end();
}
});
但这让我无法使用我的中间件。有谁知道上面的TypeError: domain.enter is not a function 可能是什么原因造成的? :(
解决方案
原来我在 timeout-middleware 之后有几个额外的中间件,这导致了这个错误。我没有找到根本原因,但是我最终添加了这个中间件:
function timeout(ms) {
let id = null;
return function(req, res, next) {
id = setTimeout(() => { if (!res.headersSent) res.status(503).end(); }, ms);
res.on('finish', () => { clearTimeout(id); });
next();
};
};
这实际上是我最初想要的,不管有多少中间件被链接起来。
【问题讨论】:
标签: node.js express request timeout connect