node.js 如何在 Node 中的 http.request() 上设置超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6214902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set a timeout on a http.request() in Node?
提问by Claudio
I'm trying to set a timeout on an HTTP client that uses http.request with no luck. So far what I did is this:
我正在尝试在使用 http.request 的 HTTP 客户端上设置超时,但没有运气。到目前为止,我所做的是:
var options = { ... }
var req = http.request(options, function(res) {
// Usual stuff: on(data), on(end), chunks, etc...
}
/* This does not work TOO MUCH... sometimes the socket is not ready (undefined) expecially on rapid sequences of requests */
req.socket.setTimeout(myTimeout);
req.socket.on('timeout', function() {
req.abort();
});
req.write('something');
req.end();
Any hints?
任何提示?
采纳答案by Sergei Kovalenko
Just to clarify the answer above:
Now it is possible to use timeoutoption and the corresponding request event:
现在可以使用timeout选项和相应的请求事件:
// set the desired timeout in options
const options = {
//...
timeout: 3000,
};
// create a request
const request = http.request(options, response => {
// your callback here
});
// use its "timeout" event to abort the request
request.on('timeout', () => {
request.abort();
});
回答by Rob Evans
2019 Update
2019年更新
There are various ways to handle this more elegantly now. Please see some other answers on this thread. Tech moves fast so answers can often become out of date fairly quickly. My answer will still work but it's worth looking at alternatives as well.
现在有多种方法可以更优雅地处理这个问题。请参阅此线程上的其他一些答案。技术发展很快,因此答案通常很快就会过时。我的答案仍然有效,但也值得寻找替代方案。
2012 Answer
2012 答案
Using your code, the issue is that you haven't waited for a socket to be assigned to the request before attempting to set stuff on the socket object. It's all async so:
使用您的代码,问题在于您在尝试在套接字对象上设置内容之前没有等待将套接字分配给请求。这一切都是异步的,所以:
var options = { ... }
var req = http.request(options, function(res) {
// Usual stuff: on(data), on(end), chunks, etc...
});
req.on('socket', function (socket) {
socket.setTimeout(myTimeout);
socket.on('timeout', function() {
req.abort();
});
});
req.on('error', function(err) {
if (err.code === "ECONNRESET") {
console.log("Timeout occurs");
//specific error treatment
}
//other error treatment
});
req.write('something');
req.end();
The 'socket' event is fired when the request is assigned a socket object.
当请求被分配一个套接字对象时,会触发 'socket' 事件。
回答by douwe
At this moment there is a method to do this directly on the request object:
此时有一种方法可以直接在请求对象上执行此操作:
request.setTimeout(timeout, function() {
request.abort();
});
This is a shortcut method that binds to the socket event and then creates the timeout.
这是绑定到套接字事件然后创建超时的快捷方法。
Reference: Node.js v0.8.8 Manual & Documentation
回答by Pierre Maoui
The Rob Evans anwser works correctly for me but when I use request.abort(), it occurs to throw a socket hang up error which stays unhandled.
Rob Evans anwser 对我来说工作正常,但是当我使用 request.abort() 时,它会抛出一个未处理的套接字挂断错误。
I had to add an error handler for the request object :
我必须为请求对象添加一个错误处理程序:
var options = { ... }
var req = http.request(options, function(res) {
// Usual stuff: on(data), on(end), chunks, etc...
}
req.on('socket', function (socket) {
socket.setTimeout(myTimeout);
socket.on('timeout', function() {
req.abort();
});
}
req.on('error', function(err) {
if (err.code === "ECONNRESET") {
console.log("Timeout occurs");
//specific error treatment
}
//other error treatment
});
req.write('something');
req.end();
回答by Manohar Reddy Poreddy
There is simpler method.
有更简单的方法。
Instead of using setTimeout or working with socket directly,
We can use 'timeout' in the 'options' in client uses
我们可以在客户端使用的“选项”中使用“超时”,而不是使用 setTimeout 或直接使用套接字
Below is code of both server and client, in 3 parts.
下面是服务器和客户端的代码,分为 3 部分。
Module and options part:
模块和选项部分:
'use strict';
// Source: https://github.com/nodejs/node/blob/master/test/parallel/test-http-client-timeout-option.js
const assert = require('assert');
const http = require('http');
const options = {
host: '127.0.0.1', // server uses this
port: 3000, // server uses this
method: 'GET', // client uses this
path: '/', // client uses this
timeout: 2000 // client uses this, timesout in 2 seconds if server does not respond in time
};
Server part:
服务器部分:
function startServer() {
console.log('startServer');
const server = http.createServer();
server
.listen(options.port, options.host, function () {
console.log('Server listening on http://' + options.host + ':' + options.port);
console.log('');
// server is listening now
// so, let's start the client
startClient();
});
}
Client part:
客户端部分:
function startClient() {
console.log('startClient');
const req = http.request(options);
req.on('close', function () {
console.log("got closed!");
});
req.on('timeout', function () {
console.log("timeout! " + (options.timeout / 1000) + " seconds expired");
// Source: https://github.com/nodejs/node/blob/master/test/parallel/test-http-client-timeout-option.js#L27
req.destroy();
});
req.on('error', function (e) {
// Source: https://github.com/nodejs/node/blob/master/lib/_http_outgoing.js#L248
if (req.connection.destroyed) {
console.log("got error, req.destroy() was called!");
return;
}
console.log("got error! ", e);
});
// Finish sending the request
req.end();
}
startServer();
If you put all the above 3 parts in one file, "a.js", and then run:
如果将以上 3 个部分全部放在一个文件“a.js”中,然后运行:
node a.js
then, output will be:
然后,输出将是:
startServer
Server listening on http://127.0.0.1:3000
startClient
timeout! 2 seconds expired
got closed!
got error, req.destroy() was called!
Hope that helps.
希望有帮助。
回答by SpiRail
Elaborating on the answer @douwe here is where you would put a timeout on a http request.
在此处详细说明@douwe 的答案,您可以在 http 请求上设置超时。
// TYPICAL REQUEST
var req = https.get(http_options, function (res) {
var data = '';
res.on('data', function (chunk) { data += chunk; });
res.on('end', function () {
if (res.statusCode === 200) { /* do stuff with your data */}
else { /* Do other codes */}
});
});
req.on('error', function (err) { /* More serious connection problems. */ });
// TIMEOUT PART
req.setTimeout(1000, function() {
console.log("Server connection timeout (after 1 second)");
req.abort();
});
this.abort() is also fine.
this.abort() 也很好。
回答by Udhaya
You should pass the reference to request like below
您应该将引用传递给请求,如下所示
var options = { ... }
var req = http.request(options, function(res) {
// Usual stuff: on(data), on(end), chunks, etc...
});
req.setTimeout(60000, function(){
this.abort();
}).bind(req);
req.write('something');
req.end();
Request error event will get triggered
请求错误事件将被触发
req.on("error", function(e){
console.log("Request Error : "+JSON.stringify(e));
});
回答by Ben Muircroft
For me - here is a less confusing way of doing the socket.setTimeout
对我来说 - 这是一种不那么令人困惑的方法 socket.setTimeout
var request=require('https').get(
url
,function(response){
var r='';
response.on('data',function(chunk){
r+=chunk;
});
response.on('end',function(){
console.dir(r); //end up here if everything is good!
});
}).on('error',function(e){
console.dir(e.message); //end up here if the result returns an error
});
request.on('error',function(e){
console.dir(e); //end up here if a timeout
});
request.on('socket',function(socket){
socket.setTimeout(1000,function(){
request.abort(); //causes error event ↑
});
});
回答by onteria_
Curious, what happens if you use straight net.socketsinstead? Here's some sample code I put together for testing purposes:
好奇,如果你用直接net.sockets代替会发生什么?这是我为测试目的而放在一起的一些示例代码:
var net = require('net');
function HttpRequest(host, port, path, method) {
return {
headers: [],
port: 80,
path: "/",
method: "GET",
socket: null,
_setDefaultHeaders: function() {
this.headers.push(this.method + " " + this.path + " HTTP/1.1");
this.headers.push("Host: " + this.host);
},
SetHeaders: function(headers) {
for (var i = 0; i < headers.length; i++) {
this.headers.push(headers[i]);
}
},
WriteHeaders: function() {
if(this.socket) {
this.socket.write(this.headers.join("\r\n"));
this.socket.write("\r\n\r\n"); // to signal headers are complete
}
},
MakeRequest: function(data) {
if(data) {
this.socket.write(data);
}
this.socket.end();
},
SetupRequest: function() {
this.host = host;
if(path) {
this.path = path;
}
if(port) {
this.port = port;
}
if(method) {
this.method = method;
}
this._setDefaultHeaders();
this.socket = net.createConnection(this.port, this.host);
}
}
};
var request = HttpRequest("www.somesite.com");
request.SetupRequest();
request.socket.setTimeout(30000, function(){
console.error("Connection timed out.");
});
request.socket.on("data", function(data) {
console.log(data.toString('utf8'));
});
request.WriteHeaders();
request.MakeRequest();

