Próbuję ustawić limit czasu na kliencie HTTP, który używa http.request bez powodzenia. Do tej pory to, co zrobiłem, to:
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();
Jakieś wskazówki?
Odpowiedzi:
Aby wyjaśnić powyższą odpowiedź :
Teraz można użyć
timeout
opcji i odpowiedniego zdarzenia żądania:// 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(); });
źródło
setTimeout(req.abort.bind(req), 3000);
connect
limit czasu, po ustanowieniu gniazda nie ma żadnego wpływu. Więc to nie pomoże w przypadku serwera, który utrzymuje gniazdo otwarte zbyt długo (nadal będziesz musiał zmienić swój własny za pomocą setTimeout).timeout : A number specifying the socket timeout in milliseconds. This will set the timeout before the socket is connected.
request.destroy
(abort
jest przestarzałe). Poza tym różni się odsetTimeout
Aktualizacja 2019
Obecnie istnieje wiele sposobów, aby poradzić sobie z tym bardziej elegancko. Zobacz inne odpowiedzi w tym wątku. Technologia szybko się rozwija, więc odpowiedzi często dość szybko stają się nieaktualne. Moja odpowiedź będzie nadal działać, ale warto też przyjrzeć się alternatywom.
Odpowiedź z 2012 roku
Używając twojego kodu, problem polega na tym, że nie czekałeś na przypisanie gniazda do żądania przed próbą ustawienia rzeczy na obiekcie gniazda. Wszystko jest asynchroniczne, więc:
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();
Zdarzenie „gniazdo” jest wyzwalane, gdy żądanie jest przypisane do obiektu gniazda.
źródło
req.abort()
nie wydaje się być w tej chwili standardową funkcjonalnością. Dlategosocket.on
możesz chcieć ustawić zmienną, taką jak,timeout = true
a następnie odpowiednio obsłużyć limit czasu w programie obsługi odpowiedziW tej chwili istnieje metoda, aby to zrobić bezpośrednio na obiekcie żądania:
request.setTimeout(timeout, function() { request.abort(); });
Jest to metoda skrótowa, która wiąże się ze zdarzeniem gniazda, a następnie tworzy limit czasu.
Odniesienie: Node.js v0.8.8 Podręcznik i dokumentacja
źródło
Odpowiedź Roba Evansa działa poprawnie dla mnie, ale kiedy używam request.abort (), pojawia się błąd zawieszenia gniazda, który pozostaje nieobsługiwany.
Musiałem dodać procedurę obsługi błędów dla obiektu żądania:
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();
źródło
myTimeout
funkcja? (edit: docs powiedzieć: Tak samo jak wiązania do zdarzenia limitu czasu nodejs.org/api/... )ECONNRESET
może się to zdarzyć w obu przypadkach: klient zamyka gniazdo, a serwer zamyka połączenie. Aby ustalić, czy zrobił to klient dzwoniącabort()
, jest specjalneabort
wydarzenieJest prostsza metoda.
Zamiast używać setTimeout lub pracować bezpośrednio z gniazdem,
możemy użyć 'timeout' w 'opcjach' w kliencie używa
Poniżej znajduje się kod serwera i klienta, w 3 częściach.
Moduł i część opcji:
'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 };
Część serwerowa:
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(); }); }
Część klienta:
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();
Jeśli umieścisz wszystkie powyższe 3 części w jednym pliku „a.js”, a następnie uruchomisz:
wtedy wynik będzie:
startServer Server listening on http://127.0.0.1:3000 startClient timeout! 2 seconds expired got closed! got error, req.destroy() was called!
Mam nadzieję, że to pomoże.
źródło
Dla mnie - tutaj jest mniej zagmatwany sposób wykonania
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 ↑ }); });
źródło
Omówienie odpowiedzi @douwe to miejsce, w którym można ustawić limit czasu na żądanie 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 () też jest w porządku.
źródło
Aby zgłosić żądanie, należy podać numer referencyjny, jak poniżej
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();
Zostanie wyzwolone zdarzenie błędu żądania
req.on("error", function(e){ console.log("Request Error : "+JSON.stringify(e)); });
źródło
Ciekawe, co się stanie, jeśli
net.sockets
zamiast tego użyjesz prostego ? Oto przykładowy kod, który utworzyłem do celów testowych: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();
źródło