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();
ヒントはありますか?
上記の回答 を明確にするためだけに:
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();
});
現在、これをよりエレガントに処理するさまざまな方法があります。このスレッドに関する他の回答をご覧ください。技術は急速に変化するため、回答はしばしばかなり早く古くなる可能性があります。私の答えは引き続き機能しますが、代替案も検討する価値があります。
コードを使用すると、問題は、ソケットオブジェクトにデータを設定しようとする前に、要求にソケットが割り当てられるのを待たなかったことです。それはすべて非同期ですので:
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();
要求にソケットオブジェクトが割り当てられると、「ソケット」イベントが発生します。
現時点では、リクエストオブジェクトで直接これを行うメソッドがあります。
request.setTimeout(timeout, function() {
request.abort();
});
これは、ソケットイベントにバインドしてからタイムアウトを作成するショートカットメソッドです。
Rob Evans 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();
より簡単な方法があります。
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つの部分をすべて「a.js」という1つのファイルに入れてから実行する場合:
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!
お役に立てば幸いです。
ここで@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()も大丈夫です。
以下のようにリクエストへの参照を渡す必要があります
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 ↑
});
});
好奇心が強い、代わりにストレート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();