我正在用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);
                }
            ]);
    });
}

当前回答

当我在同一个端口上错误地运行两个应用程序时,出现了这个错误。 我有一个next.js应用程序和另一个在nest.js中,都在端口8080上运行,当我查看。env文件时,我意识到它们具有相同的端口,所以我将一个从nest.js更改为3000,一切都正常工作。

我不是说这是错误的原因,但这是一种可能性。

其他回答

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

例子:

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

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

如文献所述:

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

另一个值得一提的情况(对于Linux和OS X)是,如果您使用像https这样的库来执行请求,或者如果您传递https://..。作为本地服务实例的URL,您将使用端口443,这是一个保留的私有端口,您可能会在Socket挂起或ECONNREFUSED错误中结束。

相反,使用端口3000,f.e.,并执行http请求。

下面是一个简单的例子,当我错过添加下面的例子注释代码时,我得到了相同的错误。取消注释req.end()代码将解决此问题。

var fs = require("fs");
var https = require("https");

var options = {
    host: "en.wikipedia.org",
    path: "/wiki/George_Washington",
    port: 443,
    method: "GET"
};

var req = https.request(options, function (res) {
    console.log(res.statusCode);
});


// req.end();

已经很长时间了,但另一种情况是,在服务器端执行请求需要很长时间(超过2分钟,这是express的默认值),并且服务器端没有配置超时参数。在我的情况下,我正在做客户端->服务器->服务器请求(Node.js express),我应该在服务器和客户端上的每个请求路由器上设置超时参数。 因此,在这两个服务器中,我需要通过使用设置请求超时

req.setTimeout([your needed timeout])

在路由器上。

看一看原文:

function socketCloseListener() {
  var socket = this;
  var parser = socket.parser;
  var req = socket._httpMessage;
  debug('HTTP socket close');
  req.emit('close');
  if (req.res && req.res.readable) {
    // Socket closed before we emitted 'end' below.
    req.res.emit('aborted');
    var res = req.res;
    res.on('end', function() {
      res.emit('close');
    });
    res.push(null);
  } else if (!req.res && !req._hadError) {
    // This socket error fired before we started to
    // receive a response. The error needs to
    // fire on the request.
    req.emit('error', createHangUpError());
    req._hadError = true;
  }
}

当服务器从未发送响应时,就会触发该消息。