如何在Node中设置http.request()的超时时间?

如何在Node中设置http.request()的超时时间?

问题描述:

我试图设置HTTP客户端上使用http.request没有运气的超时。到目前为止我做的是这样的:如何在Node中设置http.request()的超时时间?

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(); 

任何提示?

+1

找到了这个答案(它也可以),但我不知道是否有什么不同的http.request()http://stackoverflow.com/questions/6129240/how-to-set-timeout-for-http-createclient -in-node-js – Claudio 2011-06-02 13:22:29

好奇,如果您直接使用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(); 
+0

如果我使用套接字超时,并且一个接一个地发出两个请求(不等待第一个完成),第二个请求的套接字未定义(至少在我尝试设置超时)..也许应该有一些东西就像(“准备好”)在插座上...我不知道。 – Claudio 2011-06-02 17:18:48

+0

@Claudio你可以更新你的代码来显示多个请求吗? – 2011-06-02 17:25:55

+1

当然......这有点长,我用paste2.org,如果这不是问题:http://paste2.org/p/1448487 – Claudio 2011-06-02 17:42:47

使用你的代码,问题是你有没有等待一个插座,以试图设置的东西Socket对象之前被分配到请求。它们都是异步的:

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(); 

当请求被分配一个套接字对象时,会触发'套接字'事件。

+0

这确实是完全有意义的。问题是,现在我无法测试这个特定问题(时间流逝......)。所以我现在只能赞扬答案:)谢谢。 – Claudio 2012-03-29 13:07:28

+0

不用担心。请记住,据我所知,这只适用于最新版本的节点。我测试了以前的版本(5.0.3-pre),我认为它并没有触发套接字事件。 – 2012-03-29 16:21:31

+1

处理这个问题的另一种方法是使用一个bog标准的setTimeout调用。你需要保持setTimeout id为:var id = setTimeout(...);这样你可以取消它,如果你收到一个数据等。一个好方法是将它存储在请求对象本身,然后clearTimeout,如果你有一些数据。 – 2012-03-29 16:23:45

这时有直接请求对象上做到这一点的方法:

request.setTimeout(timeout, function() { 
    request.abort(); 
}); 

这是结合到插座事件的快捷方式,然后创建超时。

参考:Node.js v0.8.8 Manual & Documentation

+3

中正确处理超时。request.setTimeout“将套接字上的非活动超时毫秒数设置为超时。 “我认为这个问题是关于不考虑活动而超时的。 – ostergaard 2013-01-20 14:00:18

+0

请注意,与直接使用相关套接字的答案相同,req.abort()会导致一个错误事件,该事件应该由on('error')处理。 – KLoozen 2016-01-10 17:31:29

+4

request.setTimeout不会放弃请求,我们需要在超时回调中手动调用放弃。 – Udhaya 2016-02-23 05:52:04

的罗布·埃文斯anwser工作正常但对我来说,当我使用request.abort(),它发生抛出一个插座挂断错误,保持未处理。

我不得不添加一个错误处理程序请求对象:

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(); 
+1

“myTimeout”函数在哪里? (编辑:文档说:与绑定到超时事件相同https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback) – 2016-09-20 21:08:22

+0

请注意,'ECONNRESET'可以发生在两种情况:客户端关闭套接字和服务器关闭连接。要通过调用'abort()'来确定它是否由客户端完成,那么会出现“abort”事件 – Derp 2016-11-08 09:16:37

您应该通过参考请求像下面

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();

请求错误事件会得到触发

req.on("error", function(e){ 
 
     console.log("Request Error : "+JSON.stringify(e)); 
 
    });

我 - 这里是做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 ↑ 
     }); 
    }); 

有更简单的方法的不易混淆的方式。

而不是使用的setTimeout或插座直接工作,
我们可以在客户端中的“选项”使用“超时”使用

下面是服务器和客户端的代码,在3个部分。

模块和选项部分:

'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 
}; 

服务器部分:

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(); 
      }); 
} 

客户端部分:

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(); 

如果你把所有的上述3个部分在一个文件中,“一.js“,然后运行:

node a.js 

然后,输出将是:

startServer 
Server listening on http://127.0.0.1:3000 

startClient 
timeout! 2 seconds expired 
got closed! 
got error, req.destroy() was called! 

希望有所帮助。