How to set a timeout on a http.request() in Node?

Httpnode.jsTimeout

Http Problem Overview


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:

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?

Http Solutions


Solution 1 - Http

2019 Update

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

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.

Solution 2 - Http

Just to clarify the answer above:

Now it is possible to use timeout option and the corresponding request event:

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

See the docs: enter image description here

Solution 3 - Http

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

Solution 4 - Http

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.

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

Solution 5 - Http

There is simpler method.

Instead of using setTimeout or working with socket directly,
We can use 'timeout' in the 'options' in client uses

Below is code of both server and client, in 3 parts.

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:

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.

Solution 6 - Http

For me - here is a less confusing way of doing the 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 ↑
		});
	});

Solution 7 - Http

Elaborating on the answer @douwe here is where you would put a timeout on a http request.

// 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.

Solution 8 - Http

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();
});
req.write('something');
req.end();

Request error event will get triggered

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

Solution 9 - Http

Curious, what happens if you use straight net.sockets instead? Here's some sample code I put together for testing purposes:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionClaudioView Question on Stackoverflow
Solution 1 - HttpRob EvansView Answer on Stackoverflow
Solution 2 - HttpSergei KovalenkoView Answer on Stackoverflow
Solution 3 - HttpdouweView Answer on Stackoverflow
Solution 4 - HttpPierre MaouiView Answer on Stackoverflow
Solution 5 - HttpManohar Reddy PoreddyView Answer on Stackoverflow
Solution 6 - HttpBen MuircroftView Answer on Stackoverflow
Solution 7 - HttpSpiRailView Answer on Stackoverflow
Solution 8 - HttpUdhayaView Answer on Stackoverflow
Solution 9 - Httponteria_View Answer on Stackoverflow