Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js请求模块获取ETIMEDOUT和ESOCKETTIMEDOUT_Node.js_Sockets_Asynchronous_Request_Httprequest - Fatal编程技术网

Node.js请求模块获取ETIMEDOUT和ESOCKETTIMEDOUT

Node.js请求模块获取ETIMEDOUT和ESOCKETTIMEDOUT,node.js,sockets,asynchronous,request,httprequest,Node.js,Sockets,Asynchronous,Request,Httprequest,我用模块和模块的组合并行爬行了很多链接。 我注意到了很多ETIMEDOUT和ESOCKETTIMEDOUT错误,尽管使用chrome可以访问链接并快速响应 我已将请求选项中的maxSockets限制为2,将timeout限制为10000。 我使用的async.filterLimit()限制为2,甚至可以将并行度降低到每次2个请求。 因此,我有2个套接字、2个请求和10秒的超时等待来自服务器的头响应,但我得到了这些错误 在这里;s我使用的请求配置: { ... pool: {

我用模块和模块的组合并行爬行了很多链接。
我注意到了很多
ETIMEDOUT
ESOCKETTIMEDOUT
错误,尽管使用chrome可以访问链接并快速响应

我已将请求选项中的
maxSockets
限制为2,将
timeout
限制为10000。 我使用的
async.filterLimit()
限制为2,甚至可以将并行度降低到每次2个请求。 因此,我有2个套接字、2个请求和10秒的超时等待来自服务器的头响应,但我得到了这些错误

在这里;s我使用的请求配置:

{
    ...
    pool: {
        maxSockets: 2
    },
    timeout: 10000
    ,
    time: true
    ...
}
下面是我用来创建链接的代码片段:

var self = this;
async.filterLimit(resources, 2, function(resource, callback) {
    request({
        uri: resource.uri
    }, function (error, response, body) {
        if (!error && response.statusCode === 200) {
            ...
        } else {
            self.emit('error', resource, error);
        }
        callback(...);
    })
}, function(result) {
    callback(null, result);
});
我听了错误事件,我看到每当错误代码为
ETIMEDOUT
时,connect对象为true/false,因此有时是连接超时,有时不是(根据请求文档)

更新: 我决定将
maxSockets
提升到
Infinity
,这样就不会因为缺少可用的套接字而中断连接:

pool: {
    maxSockets: Infinity
}
为了控制带宽,我实现了一种
requestLoop
方法,该方法使用
maxAttemps
retryDelay
参数处理请求,以控制请求:

async.filterLimit(resources, 10, function(resource, callback) {
    self.requestLoop({
        uri: resource.uri
    }, 100, 5000, function (error, response, body) {
            var fetched = false;
            if (!error) {
                ...
            } else {
                ....
            }
            callback(...);
        });
}, function(result) {
    callback(null, result);
});
requestLoop的实现:

requestLoop = function(options, attemptsLeft, retryDelay, callback, lastError) {
    var self = this;
    if (attemptsLeft <= 0) {
        callback((lastError != null ? lastError : new Error('...')));
    } else {
        request(options, function (error, response, body) {
            var recoverableErrors = ['ESOCKETTIMEDOUT', 'ETIMEDOUT', 'ECONNRESET', 'ECONNREFUSED'];
            var e;
            if ((error && _.contains(recoverableErrors, error.code)) || (response && (500 <= response.statusCode && response.statusCode < 600))) {
                e = error ? new Error('...');
                e.code = error ? error.code : response.statusCode;
                setTimeout((function () {
                    self.requestLoop(options, --attemptsLeft, retryDelay, callback, e);
                }), retryDelay);
            } else if (!error && (200 <= response.statusCode && response.statusCode < 300)) {
                callback(null, response, body);
            } else if (error) {
                e = new Error('...');
                e.code = error.code;
                callback(e);
            } else {
                e = new Error('...');
                e.code = response.statusCode;
                callback(e);
            }
        });
    }
};
您“”注意到末尾调用了
runRequest()
。 此功能任务是在最大
activeRequests
限制
maxConcurrentRequests
的同时,管理请求并在可能的情况下激发请求:

var self = this;
process.nextTick(function() {
    var next;
    if (!self.pendingRequests.length || self.activeRequests >= self.maxConcurrentRequests) {
        return;
    }
    self.activeRequests++;
    next = self.pendingRequests.shift();
    next["function"].apply(self, next["arguments"]);
    self.runRequest();
});
这应该可以解决任何超时错误,通过我的测试,我仍然注意到在我测试过的特定网站上有一些超时。我不能100%确定这一点,但我认为这是由于支持http服务器的网站的性质,通过执行ip检查,将用户请求限制在最大值,并因此返回一些http 400消息,以防止可能对服务器的“攻击”。

编辑:重复

默认情况下,节点具有。如果您的DNS查询需要很长时间,请求将在DNS阶段被阻止,症状就是
ESOCKETTIMEDOUT
ETIMEDOUT

尝试增加uv线程池大小:

export UV_THREADPOOL_SIZE=128
node ...
或者在
index.js
中(或者您的入口点在哪里):

编辑1:关于它


编辑2:如果查询是非唯一的,您可能需要使用缓存,如。

我发现如果异步请求太多,则在linux中会发生ESOCKETTIMEDOUT异常。我发现的解决方法是:

将此选项设置为request():

代理:false,池:{maxSockets:100}

请注意,在此之后,超时时间可能会延迟,因此您可能需要增加超时时间

你有没有弄明白@Jorayen?@DvideBy0更新了一个解决方案我发现我的代码有点不同。就底层套接字而言,似乎没有考虑在代码中设置超时。我必须等待套接字事件(见下文)。on('socket',function(socket){socket.setTimeout(30000);socket.on('timeout',function(){request.abort();logger.error('request timeout out out out out after 30秒');};})感谢您对本主题的有益补充,我还没有测试您的建议,但知道这一点很好。我也会在有空的时候报告结果:)我读到的关于UV_THREADPOOL_SIZE的内容表明,这对于阻止io(如磁盘访问)最为重要,但对于非阻止io(如网络访问)则无关紧要。这是正确的,除了DNS解析也会被阻止,因为
getaddrinfo(3)
有效。首先,这对我来说很有效,因为我下载了几百个小文件,导致了这个错误。第二,增加插座数量的缺点是什么?它们会在某个时候自动关闭吗?
export UV_THREADPOOL_SIZE=128
node ...
#!/usr/bin/env node
process.env.UV_THREADPOOL_SIZE = 128;

function main() {
   ...
}