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

Cla*_*dio 82 timeout http node.js

我正在尝试在没有运气的情况下使用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();
Run Code Online (Sandbox Code Playgroud)

任何提示?

Rob*_*ans 91

使用您的代码,问题是您在尝试在套接字对象上设置内容之前没有等待将套接字分配给请求.这一切都是异步的:

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();
Run Code Online (Sandbox Code Playgroud)

在为请求分配套接字对象时会触发'socket'事件.

  • 您能提到一种更优雅的解决方案吗?如果没有更多信息,说有更优雅的解决方案并没有多大帮助 (2认同)

dou*_*uwe 38

此时有一种方法可以直接在请求对象上执行此操作:

request.setTimeout(timeout, function() {
    request.abort();
});
Run Code Online (Sandbox Code Playgroud)

这是一种绑定到套接字事件然后创建超时的快捷方法.

参考:Node.js v0.8.8手册和文档

  • request.setTimeout不会中止请求,我们需要在超时回调中手动调用abort. (4认同)
  • request.setTimeout"在套接字上的超时毫秒不活动后将套接字设置为超时." 我认为这个问题是关于超时请求的,不管活动如何. (3认同)

Pie*_*oui 18

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();
Run Code Online (Sandbox Code Playgroud)

  • `myTimeout`函数在哪里?(编辑:文档说:与绑定到超时事件相同https://nodejs.org/api/http.html#http_request_settimeout_timeout_callback) (2认同)

Ser*_*nko 10

只是为了澄清以上答案

现在可以使用timeoutoption和相应的request事件:

// 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();
});
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这严格来说是“连接”超时,一旦建立套接字,它就不起作用。因此,这对于使套接字保持打开时间过长的服务器没有帮助(您仍然需要使用 setTimeout 进行自己的操作)。`timeout :指定套接字超时的数字(以毫秒为单位)。这将在连接套接字之前设置超时。 (6认同)
  • 这就是我在挂起的连接尝试中寻找的内容。当尝试访问未侦听的服务器上的端口时,可能会发生挂起的连接。顺便说一句,API 已更改为“request.destroy”(“abort”已弃用。)此外,这与“setTimeout”不同 (2认同)

Man*_*ddy 7

有更简单的方法.


我们可以在客户端使用的'options'中使用'timeout',而不是使用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
};
Run Code Online (Sandbox Code Playgroud)

服务器部分:

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();
            });
}
Run Code Online (Sandbox Code Playgroud)

客户部分:

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();
Run Code Online (Sandbox Code Playgroud)

如果将上述3个部分放在一个文件"a.js"中,然后运行:

node a.js
Run Code Online (Sandbox Code Playgroud)

然后,输出将是:

startServer
Server listening on http://127.0.0.1:3000

startClient
timeout! 2 seconds expired
got closed!
got error, req.destroy() was called!
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.