Express.js响应超时

105

问题

我一直在寻找Express.js的请求/响应超时设置,但似乎所有的内容都与连接有关,而不是与请求/响应本身有关。

如果一个请求花费了很长时间,它应该被超时。显然这种情况不应该发生,但即使是简单的错误,比如没有调用回调函数或没有使用res.send(),浏览器也会永远等待回复。

一个空的路由处理程序就是这样的一个典型例子。

app.get('/sessions/', function(req, res, callback){});

修复

我在 app.use(app,router); 前添加了以下内容,似乎添加了超时功能。有人有相关经验/意见吗?

app.use(function(req, res, next){
    res.setTimeout(120000, function(){
        console.log('Request has timed out.');
            res.send(408);
        });

    next();
});

请注意,我已将超时时间设置为2分钟。


2
我只会将其用于开发目的 - 我想不出任何一种情况,你会想要在生产代码中使用空路由。 - srquinn
当然,我的意思是可能会出现请求一直等待的问题。错误时有发生的。我只是想设置一个响应超时以防万一。 - Xerri
抓住 - 请参见下面的答案。 - srquinn
10
空路由是否会成为网络爬虫的陷阱? - prototype
当我尝试使用Express.js(实际上是json-server)构建测试服务以模拟/诱导服务器端的各种错误条件时,这个“特性”非常有用。大多数此类错误对应于HTTP状态码(例如,Bad Request),但我还想在调用方端引发SocketTimeoutException。 - Ferenc Dósa-Rácz
如果响应超时的值大于HTTP超时,会发生什么? - 欧阳维杰
9个回答

87

已经存在一个用于超时支持的连接中间件:

var timeout = express.timeout // express v3 and below
var timeout = require('connect-timeout'); //express v4

app.use(timeout(120000));
app.use(haltOnTimedout);

function haltOnTimedout(req, res, next){
  if (!req.timedout) next();
}
如果您计划像上面那样将超时中间件用作顶级中间件,则haltOnTimedOut中间件需要是定义的堆栈中的最后一个中间件,并用于捕获超时事件。感谢@Aichholzer的更新。
附注: 请记住,如果您自己编写超时中间件,则4xx状态代码表示客户端错误,而5xx状态代码表示服务器错误。 408用于以下情况:
客户端在服务器准备等待的时间内没有产生请求。客户端可以在任何以后的时间重复请求而不进行修改。

完美。甚至更简单。谢谢您提供的错误信息提示。 - Xerri
3
根据官方文档,不建议将其作为顶级中间件使用,至少不要这样简单地使用。https://github.com/expressjs/timeout - Stefan
这个答案似乎没有增加套接字超时时间就相当无用了。 - Jeff Fischer
1
@SuperUberDuper:请将您的问题单独发布为一个新的问题,以便社区可以帮助您解决特定的问题。 - srquinn
@Fe3back 这通常表示您的代码中存在竞态条件/多次调用req.send() - undefined
显示剩余6条评论

83

你不需要其他npm模块来实现这个

var server = app.listen();
server.setTimeout(500000);

https://github.com/expressjs/express/issues/3330启发

或者

app.use(function(req, res, next){
    req.setTimeout(500000, function(){
        // call back function is called when request timed out.
    });
    next();
});

这是一篇非常老的帖子,但我没有使用任何额外的模块。请查看问题中的“修复”部分。 - Xerri
req.setTimeout not res.setTimeout - DollarAkshay
我的实验表明,req.setTimeout()回调根本没有被调用,并且server.setTimeout()没有关闭连接并且没有停止请求被处理。因此,提供的解决方案是不完整的。 - Slava Fomin II
2
我的测试中req.setTimeoutres.setTimeout都在正常工作。 - Michael Cox
2
res.setTimeout对我起作用了,而不是req。 - Paul Fabbroni

36

如果您正在使用Express 4.2,则需要手动添加超时中间件,因为它已被删除。添加方式如下:

npm install connect-timeout

并且在代码中它必须是(根据评论编辑,如何将其包含在代码中)。

 var timeout = require('connect-timeout');
 app.use(timeout('100s'));

1
没有使用过DV,但有些人可能需要使用var timeout = require('connect-timeout')他们不得不在谷歌上搜索它 =) - Mohamed Salad

5

如果您想使用超时中间件并排除特定路由:

var timeout = require('connect-timeout');
app.use(timeout('5s')); //set 5s timeout for all requests

app.use('/my_route', function(req, res, next) {
    req.clearTimeout(); // clear request timeout
    req.setTimeout(20000); //set a 20s timeout for this request
    next();
}).get('/my_route', function(req, res) {
    //do something that takes a long time
});

1
如果您需要测试您的API,这个解决方案可以帮助您。 我在中间件中使用它来测试我的前端。 例如:如果您需要测试前端中的装载器。
const router = require('express').Router();
const { data } = require('./data');

router.get('/api/data', (req, res, next) => {
  setTimeout(() => {
      res.set('Content-Type', 'application/json')
      res.status(200).send(data)

      next()
  }, 2000)
})

module.exports = router;

0
希望还不算太晚,这是我从@Elliot404那里得到的解决方案,正是我一直在寻找的。 希望它能有所帮助。
export const timeOutMiddleWare = (
  req: Request,
  res: Response,
  next: NextFunction,
) => {
  setTimeout(() => {
    if (!res.headersSent) {
      res.status(408).send(`${req.method} ${req.originalUrl} Timed Out`);
      req.socket.end();
      res.json = () => {};
      res.send = () => {};
      res.sendStatus = () => {};
    }
  }, 1000 * 60 * 5);
  next();
};

-1

-3

您可以尝试以下方法:

return await new Promise((resolve) =>
  setTimeout(() => {
    resolve(resp);
  }, 3000),
);

在上面的代码中,3000 = 3秒。根据您的要求进行更改。
虽然我没有尝试过很长时间的场景。请在评论中告诉我结果。

-20
在设置路由之前,请添加以下代码:

app.all('*', function(req, res, next) {
    setTimeout(function() {
        next();
    }, 120000); // 120 seconds
});

34
这难道不就是在回复客户之前等待120秒吗? - Jeffrey van Norden
5
@JeffreyvanNorden 这正是我为了调试目的所寻找的。 - 5ervant - techintel.github.io
2
具有讽刺意味的是,这正是我正在寻找的。 - AndrewLeonardi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接