Node.js&Express.js HTTP应用超时设置

 2016年02月28日    9663     声明


Node.js创建的HTTP服务器,其对于每个客户端请求的默认连接时长是2分钟(120秒)。如果在这个时间内,服务器没有发送响应信息(response),客户端的连接就会被重置。时间过长的请求响应会造成极差的用户体验,而且会造成IO的阻塞,对于单线程运行的Node.js应用来说,这种影响简直是灾难性的。合理的设置应用的超时时间非常重要。


  1. Node.jshttp模块对超时的处理
  2. Express.js的超时设置

1. Node.jshttp模块对超时的处理

在Node.js中,创建一个HTTP服务器使用http模块

1.1 创建一个HTTP服务器

使用Node.js的http模块,可以很简单实现一个HTTP服务器:

const http = require('http');

const hostname = '127.0.0.1';
const port = 1337;

var server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end('Hello World\n');
})
server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

在上面的示例中,我们使用http.createServer创建了一个HTTP服务器server,它是一个http.Server实例。

在这个服务器中,我们添加了一个HTTP客户端请求监听函数,该函数包括两个参数:reqres。其中,req是一个客户端请求对象包含了客户端的请求信息,它是一个http.IncomingMessage实例。而res是服务器响应对象,它是一个http.ServerResponse实例,服务器处理完用户请求后通过访对象向客户端返回响应信息


1.2 http模块的超时设置

服务端的超时设置

对于一个HTTP服务器来说,我们可能会设置以下两种类型的超时:

  • 用户请求的超时:即上例中http.IncomingMessage实例-req

    用户请求时间过长,会导致服务器停留在一个用户请求的接收状态,从而阻碍其它用户请求的进入。

  • 服务器响应的超时:即上例中http.ServerResponse实例-res

    服务器响应时间过长,会导致用户长时间接收不到服务器响应信息,影响用户体验和其它用户请求的处理

Node.js HTTP服务器设置超时使用setTimeout()方法。http.Serverhttp.IncomingMessagehttp.ServerResponse中都有一个setTimeout()方法。server.setTimeout()会设置所有用户请求和服务器响应的超时时间,而req.setTimeout()只能针对本次请求超时时间进行设置,res.setTimeout()只能针对本次请求的服务器响应超时时间进行设置。我们可以像下面这样在HTTP服务端设置超时:

将所有的用户请求和服务器响应超时时间设置为5秒:

server.setTimeout(5000);

对于某一个比较耗时的用户请求(如:图片上传),我们将用户请求超时时间设置为20秒:

req.setTimeout(20*1000);

对于一个需要在服务器进行较长时间处理用户请求,我们将服务器响应的超时时间设置为10秒:

res.setTimeout(10*1000);


客户端的超时设置

Node.js的http模块除了可以做为HTTP服务器使用,来处理和响应用户请求外。还可以做为HTTP客户端来使用,来发送客户端请求。

http模块中的ClientRequest对象实现了HTTP客户端功能,该对象同样提供了一个setTimeout()方法,用于设置请求的超时时间,当服务器超时未响应时,客户端对象会重置到服务器的链接。

如,我们可以像下面这样创建一个HTTP客户端,并设置请求的超时时间:

const http = require('http');

const options = {
  host: 'itbilu.com',
  method: 'GET',
  port: 80,
  path: '/'
}
var req = http.request(options);
req.setTimeout(2000);
req.on('response', (res) => {
  res.setEncoding('utf8');
  res.on('data', function(chunk){
	console.log('收到数据:%s', chunk);
  });
  res.on('end', function(){
	console.log(res.trailers);
  });
});
req.end();


注意:所有的超时设置都是以毫秒为单位,当设置为0时表示永不超时。


2. Express.js的超时设置

Express.js框架是在http模块的基础上构建的一个HTTP服务器模块,因此我们也可以像http模块那样设置所有HTTP请求的用户请求和服务器响应超时时间,也可以针对某一个HTTP请求设置用户请求和服务器响应超时时间。

2.1 Express.js所有的请求超时时间

类似Node.js原生的HTTP服务器设置,我们对Express.js应用所有请求的用户请求和服务器响应超时时间进行设置:

var app = require('../app');

app.set('port', process.env.PORT || 3000);

var server = app.listen(app.get('port'), function() {
  debug('Express服务器运行于:' + server.address().port);
});

server.setTimeout(1000);
server.on('timeout', function(){
  console.log('超时了');
})


2.2 使用Express.js中间件设置超时

Express.js提供了强大的中间件机制,利用这一机制我们可以更为灵活的设置HTTP服务器超时时间。

如,我们可以在app.js文件中添加如下处理程序,分别设置请求和服务器响应的超时时间,当然也可以只设置请求超时或服务器响应超时时间:

app.use(function(req, res, next) {
  // 设置所有HTTP请求的超时时间
  req.setTimeout(5000);
  // 设置所有HTTP请求的服务器响应超时时间
  res.setTimeout(5000);
  next();
});

对比较某一个比较耗时的用户请求,或需要较多响应时间才能完成处理的请求,我们可以其路由处理方法或路由中间件中单独设置超时时间:

router.post('/file', function(req, res) {
  req.setTimeout(20*1000)
  // 一些处理……  
});