我正在用Node和Cheerio构建一个网页刮板,对于某个网站,我得到以下错误(它只发生在这一个网站上,没有其他我试图刮的网站。

它每次都发生在不同的位置,所以有时是url x抛出错误,其他时候url x是好的,它是一个完全不同的url:

    Error!: Error: socket hang up using [insert random URL, it's different every time]

Error: socket hang up
    at createHangUpError (http.js:1445:15)
    at Socket.socketOnEnd [as onend] (http.js:1541:23)
    at Socket.g (events.js:175:14)
    at Socket.EventEmitter.emit (events.js:117:20)
    at _stream_readable.js:910:16
    at process._tickCallback (node.js:415:13)

这是非常棘手的调试,我真的不知道从哪里开始。首先,什么是套接字挂起错误?是404错误还是类似的错误?或者仅仅意味着服务器拒绝连接?

我在任何地方都找不到解释!

编辑:下面是(有时)返回错误的代码示例:

function scrapeNexts(url, oncomplete) {
    request(url, function(err, resp, body) {

        if (err) {
            console.log("Uh-oh, ScrapeNexts Error!: " + err + " using " + url);
            errors.nexts.push(url);
        }
        $ = cheerio.load(body);
        // do stuff with the '$' cheerio content here
    });
}

没有直接调用关闭连接,但我使用节点请求(据我所知)使用http。get所以这是不需要的,如果我错了纠正我!

编辑2:下面是一段实际使用的代码,它会导致错误。prodURL和其他变量主要是前面定义的jquery选择器。这使用了Node的异步库。

function scrapeNexts(url, oncomplete) {
    request(url, function (err, resp, body) {

        if (err) {
            console.log("Uh-oh, ScrapeNexts Error!: " + err + " using " + url);
            errors.nexts.push(url);
        }
        async.series([
                function (callback) {
                    $ = cheerio.load(body);
                    callback();
                },
                function (callback) {
                    $(prodURL).each(function () {
                        var theHref = $(this).attr('href');
                        urls.push(baseURL + theHref);
                    });
                    var next = $(next_select).first().attr('href');
                    oncomplete(next);
                }
            ]);
    });
}

当前回答

有两种情况下套接字挂起被抛出:

当你是客户的时候

您作为客户端向远程服务器发送请求,但没有收到及时响应。您的套接字已结束,从而抛出此错误。您应该捕捉这个错误并决定如何处理它:是否重试请求,是否将其排队等待,等等。

当您是服务器/代理时

当您作为服务器(可能是代理服务器)接收来自客户机的请求,然后开始对其进行操作(或将请求中继到上游服务器),并且在您准备好响应之前,客户机决定取消/中止请求。

此堆栈跟踪显示客户端取消请求时发生的情况。

Trace: { [Error: socket hang up] code: 'ECONNRESET' }
    at ClientRequest.proxyError (your_server_code_error_handler.js:137:15)
    at ClientRequest.emit (events.js:117:20)
    at Socket.socketCloseListener (http.js:1526:9)
    at Socket.emit (events.js:95:17)
    at TCP.close (net.js:465:12)

行http.js:1526:9指向@Blender提到的相同的socketCloseListener,特别是:

// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());

...

function createHangUpError() {
  var error = new Error('socket hang up');
  error.code = 'ECONNRESET';
  return error;
}

如果客户端是浏览器中的用户,这是一个典型的情况。加载某些资源/页面的请求需要很长时间,用户只需刷新页面。此操作将导致前一个请求中止,从而在服务器端抛出此错误。

由于此错误是由客户端意愿引起的,因此他们不期望收到任何错误消息。所以,没有必要认为这个错误是严重的。忽略它。这是鼓励的事实,在这样的错误,你的客户端侦听的res套接字,虽然仍然是可写的,销毁。

console.log(res.socket.destroyed); //true

因此,除了显式关闭响应对象外,没有发送任何东西:

res.end();

但是,如果您是一个代理服务器,并且已经将请求转发给了上游服务器,那么您应该做的是终止发送给上游服务器的内部请求,这表明您对响应不感兴趣,这反过来可能会告诉上游服务器停止昂贵的操作。

其他回答

您的问题也可能来自试图连接到HTTP URL,而您的服务仅在HTTPS上发布…

绝对是一个耗时的错误!

我在使用Nano库连接Couch DB时也遇到了同样的问题。我尝试使用keepaliveagent库微调连接池,它一直失败的套接字挂起消息。

var KeepAliveAgent = require('agentkeepalive');

var myagent = new KeepAliveAgent({
    maxSockets: 10,
    maxKeepAliveRequests: 0,
    maxKeepAliveTime: 240000
});

nano = new Nano({
    url : uri,
    requestDefaults : {
        agent : myagent
    }
});

经过一番努力,我终于解决了这个问题——结果发现这是一个非常非常简单的错误。我通过HTTPS协议连接到数据库,但是我一直向我的nano对象传递一个keepalive代理,作为使用这个库显示的示例创建(它们依赖于一些使用http的默认值)。

使用httpagent时做了一个简单的改变:

var KeepAliveAgent = require('agentkeepalive').HttpsAgent;

有两种情况下套接字挂起被抛出:

当你是客户的时候

您作为客户端向远程服务器发送请求,但没有收到及时响应。您的套接字已结束,从而抛出此错误。您应该捕捉这个错误并决定如何处理它:是否重试请求,是否将其排队等待,等等。

当您是服务器/代理时

当您作为服务器(可能是代理服务器)接收来自客户机的请求,然后开始对其进行操作(或将请求中继到上游服务器),并且在您准备好响应之前,客户机决定取消/中止请求。

此堆栈跟踪显示客户端取消请求时发生的情况。

Trace: { [Error: socket hang up] code: 'ECONNRESET' }
    at ClientRequest.proxyError (your_server_code_error_handler.js:137:15)
    at ClientRequest.emit (events.js:117:20)
    at Socket.socketCloseListener (http.js:1526:9)
    at Socket.emit (events.js:95:17)
    at TCP.close (net.js:465:12)

行http.js:1526:9指向@Blender提到的相同的socketCloseListener,特别是:

// This socket error fired before we started to
// receive a response. The error needs to
// fire on the request.
req.emit('error', createHangUpError());

...

function createHangUpError() {
  var error = new Error('socket hang up');
  error.code = 'ECONNRESET';
  return error;
}

如果客户端是浏览器中的用户,这是一个典型的情况。加载某些资源/页面的请求需要很长时间,用户只需刷新页面。此操作将导致前一个请求中止,从而在服务器端抛出此错误。

由于此错误是由客户端意愿引起的,因此他们不期望收到任何错误消息。所以,没有必要认为这个错误是严重的。忽略它。这是鼓励的事实,在这样的错误,你的客户端侦听的res套接字,虽然仍然是可写的,销毁。

console.log(res.socket.destroyed); //true

因此,除了显式关闭响应对象外,没有发送任何东西:

res.end();

但是,如果您是一个代理服务器,并且已经将请求转发给了上游服务器,那么您应该做的是终止发送给上游服务器的内部请求,这表明您对响应不感兴趣,这反过来可能会告诉上游服务器停止昂贵的操作。

我使用require('http')来消费https服务,它显示“套接字挂起”。

然后我把require('http')改为require('https'),它正在工作。

在使用http时也会发生此错误。请求,可能您的请求还没有完成。

例子:

Const req = https。请求(options, res => {})

你总是需要添加这一行: 有了这个功能,我们将按顺序完成请求的发送。

如文献所述:

对于http.request(),必须总是调用req.end()来表示请求的结束——即使没有数据写入请求体。