web-dev-qa-db-fra.com

Comment définir un délai d'attente sur un http.request () dans Node?

J'essaie de définir un délai d'attente sur un client HTTP qui utilise http.request sans succès. Jusqu'ici, ce que j'ai fait est la suivante:

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

Des allusions?

81
Claudio

Juste pour clarifier le réponse ci-dessus :

Il est maintenant possible d’utiliser l’option timeout et l’événement de requête correspondant:

// 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();
});
8
Sergei Kovalenko

Mise à jour 2019

Il existe différentes manières de gérer cela de manière plus élégante maintenant. S'il vous plaît voir d'autres réponses sur ce fil. La technologie évolue rapidement, de sorte que les réponses peuvent souvent devenir obsolètes assez rapidement. Ma réponse fonctionnera toujours, mais il convient également d'examiner d'autres solutions.

Réponse 2012

En utilisant votre code, le problème est que vous n'avez pas attendu l'affectation d'un socket à la demande avant de tenter de définir des commandes sur l'objet socket. C'est tout async donc:

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

L'événement 'socket' est déclenché lorsque la demande est affectée à un objet socket.

89
Rob Evans

À ce moment, il existe une méthode pour le faire directement sur l'objet de requête:

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

Il s'agit d'une méthode de raccourci qui se lie à l'événement socket, puis crée le délai d'expiration.

Référence: Manuel et documentation Node.js v0.8.8

38
douwe

L’analyseur Rob Evans fonctionne correctement pour moi, mais lorsque j’utilise request.abort (), il se produit une erreur de raccrochage de socket qui reste non gérée.

J'ai dû ajouter un gestionnaire d'erreurs pour l'objet de requête:

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();
18
Pierre Maoui

Il y a une méthode plus simple.

Au lieu d’utiliser setTimeout ou de travailler directement avec socket,
Nous pouvons utiliser "timeout" dans les "options" des utilisations client

Vous trouverez ci-dessous le code du serveur et du client, en 3 parties.

Partie module et options:

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

Partie serveur:

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

Partie client:

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

Si vous mettez toutes les 3 parties ci-dessus dans un seul fichier, "a.js", puis exécutez:

node a.js

alors, la sortie sera:

startServer
Server listening on http://127.0.0.1:3000

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

J'espère que ça t'as aidé.

7

En développant la réponse, @douwe est l'endroit où vous voudriez mettre un délai d'attente sur une requête 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 () est également bon.

2
SpiRail

Vous devriez passer la référence à la demande comme ci-dessous

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

L'événement d'erreur de requête sera déclenché

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

Pour moi - voici une façon moins déroutante de faire le 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 ↑
        });
    });
2
Ben Muircroft

Curieux, que se passe-t-il si vous utilisez straight net.sockets au lieu? Voici un exemple de code que j'ai mis en place à des fins de test:

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
onteria_