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

看一看原文:

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;
  }
}

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


扩展Blender的答案,这在很多情况下都会发生。我遇到的最常见的问题是:

服务器崩溃。 服务器拒绝您的连接,很可能被用户代理阻塞。

socketCloseListener,正如Blender的回答中所概述的那样,并不是创建挂机错误的唯一地方。

例如,可以在这里找到:

function socketOnEnd() {
  var socket = this;
  var req = this._httpMessage;
  var parser = this.parser;

  if (!req.res) {
    // If we don't have a response then we know that the socket
    // ended prematurely and we need to emit an error on the request.
    req.emit('error', createHangUpError());
    req._hadError = true;
  }
  if (parser) {
    parser.finish();
    freeParser(parser, req);
  }
  socket.destroy();
}

你可以用curl来处理从Node发出的头信息,看看你是否得到响应。如果您没有使用curl得到响应,但在浏览器中得到响应,那么您的User-Agent头很可能被阻塞。


一个值得一提的例子:当使用Express从Node.js连接到Node.js时,如果我没有在请求的URL路径前面加上“/”,我就会得到“套接字挂起”。


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

当你是客户的时候

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

当您是服务器/代理时

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

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

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

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


我在使用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;

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

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


在我的例子中,这是因为应用程序/json响应的格式很糟糕(包含堆栈跟踪)。响应从未发送到服务器。 这对调试来说非常棘手,因为没有日志。这篇文章帮助我理解发生了什么。


如果您正在使用node-http-proxy,请注意这个问题,这将导致套接字挂起错误:https://github.com/nodejitsu/node-http-proxy/issues/180。

为了解决这个问题,同样在这个链接中,只需在express. bodyparser()之前移动在快速路由中声明API路由(用于代理)。


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

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


昨天通过IntelliJ IDEA 2016.3.6运行我的web应用程序和node.js服务器时遇到了这个问题。我所要做的就是清除我的cookie并在Chrome浏览器中缓存。


我在请求某些服务器时遇到了同样的问题。在我的例子中,在请求选项的头中将任何值设置为User-Agent都对我有帮助。

const httpRequestOptions = {
    hostname: 'site.address.com',
    headers: {
       'User-Agent': 'Chrome/59.0.3071.115'
    }
};

这不是一般情况,取决于服务器设置。


我同时做web(节点)和Android开发,并一起打开Android Studio设备模拟器和docker,它们都使用端口8601,它抱怨套接字挂起错误,关闭Android Studio设备模拟器后,它在节点端工作良好。不要同时使用Android Studio设备模拟器和docker。


如果您在https连接上遇到此错误,并且它立即发生,则可能是设置SSL连接有问题。

对我来说,它是这个问题https://github.com/nodejs/node/issues/9845但对你来说,它可能是其他东西。如果ssl存在问题,那么您应该能够使用nodejs tls/ssl包重新生成它,只是试图连接到域


我认为值得注意的是……

我正在为谷歌api创建测试。我用一个临时服务器拦截请求,然后转发给真正的api。我试图在请求中传递头部,但一些头部导致了另一端的express问题。

也就是说,在使用请求模块进行转发之前,我必须删除连接、接受和内容长度的报头。

let headers = Object.assign({}, req.headers);
delete headers['connection']
delete headers['accept']
delete headers['content-length']
res.end() // We don't need the incoming connection anymore
request({
  method: 'post',
  body: req.body,
  headers: headers,
  json: true,
  url: `http://myapi/${req.url}`
}, (err, _res, body)=>{
  if(err) return done(err);
  // Test my api response here as if Google sent it.
})

下面是一个简单的例子,当我错过添加下面的例子注释代码时,我得到了相同的错误。取消注释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();

对于请求模块用户

超时 有两种主要类型的超时:连接超时和读取超时。如果在客户端试图建立到远程机器的连接(对应于套接字上的connect()调用)时超时,则会发生连接超时。当服务器太慢而无法发送回部分响应时,就会发生读超时。

注意,连接超时发出一个ETIMEDOUT错误,读取超时发出一个ECONNRESET错误。


另一个原因可能是因为在创建服务器套接字时使用了express的应用实例而不是从const server = http.createServer(app)中创建的服务器实例。

错误的

const express = require('express');
const http = require('http');
const WebSocket = require('ws');


const app = express();

app.use(function (req, res) {
  res.send({ msg: "hello" });
});

const wss = new WebSocket.Server({ server: app }); // will throw error while connecting from client socket

app.listen(8080, function listening() {
  console.log('Listening on %d', server.address().port);
});

正确的

const express = require('express');
const http = require('http');
const WebSocket = require('ws');


const app = express();

app.use(function (req, res) {
  res.send({ msg: "hello" });
});

const server = http.createServer(app);
const wss = new WebSocket.Server({ server });

server.listen(8080, function listening() {
  console.log('Listening on %d', server.address().port);
});

这给我带来了问题,因为我正在做这里列出的所有事情,但仍然抛出错误。事实证明,调用req.abort()实际上会抛出一个带有ECONNRESET代码的错误,因此您实际上必须在错误处理程序中捕获该错误。

req.on('error', function(err) {
    if (err.code === "ECONNRESET") {
        console.log("Timeout occurs");
        return;
    }
    //handle normal errors
});

我的情况下,这不是一个错误,但预期行为chrome浏览器。Chrome保持tls连接活跃(我认为是为了速度),但node.js服务器在2分钟后停止它,你会得到一个错误。

如果你尝试GET请求使用边缘浏览器,将不会有任何错误。 如果你将关闭chrome窗口-你会得到错误马上。

那么该怎么办呢? 1)你可以过滤这些错误,因为它们不是真正的错误。 2)也许有更好的解决方案:)


这里似乎还有一个额外的情况,那就是Electron不喜欢“localhost”域名。在我的情况下,我需要改变这个:

const backendApiHostUrl = "http://localhost:3000";

:

const backendApiHostUrl = "http://127.0.0.1:3000";

从那以后,问题就消失了。

这意味着DNS解析(本地或远程)也可能导致一些问题。


我在OCP集群上使用CouchDB时得到了类似的错误。

const cloudantSessionStore = sessionStore.createSessionStore(
  {
    type: 'couchdb',
    host: 'https://' + credentials['host'],
    port: credentials['port'],
    dbName: 'sessions',
    options: {
      auth: {
        username: credentials['username'],
        password: credentials['password']
      },
      cache: false
    }
  }

它应该是“http”,而不是“https”,以连接我的CouchDB实例。希望对遇到类似问题的人有所帮助。


经过长时间的调试到节点js代码,mongodb连接字符串,检查CORS等,对我来说,只是切换到不同的端口号server.listen(端口);成功了,邮差,你也试试。不更改代理设置,只更改默认值。


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

例子:

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

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

如文献所述:

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


我认为“套接字挂起”是一个相当普遍的错误,表明连接已从服务器端终止。换句话说,用于维护客户端和服务器之间连接的套接字已经断开。(虽然我确信上面提到的许多观点对不同的人都有帮助,但我认为这是更普遍的答案。)

In my case, I was sending a request with a payload in excess of 20K. This was rejected by the server. I verified this by removing text and retrying until the request succeeded. After determining the maximum acceptable length, I verified that adding a single character caused the error to manifest. I also confirmed that the client wasn't the issue by sending the same request from a Python app and from Postman. So anyway, I'm confident that, in my case, the length of the payload was my specific problem.

同样,问题的根源是坊间传闻。常见的问题是“服务器说不”。


我用的是nano,我花了很长时间才发现这个错误。我的问题是我使用了错误的端口。我的端口是5948而不是5984。

var nano = require('nano')('http://localhost:5984');
var db = nano.use('address');
var app = express();

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

req.setTimeout([your needed timeout])

在路由器上。


可能是您的服务器或Socket连接意外崩溃。


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

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


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

绝对是一个耗时的错误!


在Azure静态Web应用程序(SWA)模拟器中获得“[GET] localhost:4200, Socket hang up”。

解决方案是从angular.json中删除这个:

"headers": {"cross-origin-opener-policy": "same-origin-allow-popups"}

我使用带有x.509证书身份验证的axios

我的请求是这样的。

 async function callService() {

     const httpsAgent = new https.Agent({
         cert: fs.readFileSync('client.crt'),
         key: fs.readFileSync('client.key'),
         ca: fs.readFileSync('ca.crt'),
     });

     try {
         const result = await axios.post(
             'https://example.com/test/', 
             {"topic": 'home'}, 
             { httpsAgent: httpsAgent }
         );
     }
     catch (error) {
         console.log('error:', error)
     }

}

client.crt 
-----BEGIN CERTIFICATE-----
MIIDWjC....cME70g==
-----END CERTIFICATE-----

client.key
-----BEGIN RSA PRIVATE KEY-----
oBXxnIVby...qvdSsQ==
-----END RSA PRIVATE KEY-----

ca.crt
-----BEGIN CERTIFICATE-----
MIIDQ...8SQvvG5
-----END CERTIFICATE-----

我得到了错误:

Error: socket hang up
at connResetException (internal/errors.js:609:14)
at TLSSocket.socketOnEnd (_http_client.js:458:23)
at TLSSocket.emit (events.js:326:22)

解决方案:

我发现我使用的证书是无效的。: -)


我在nodejs中使用axios,在从url获取数据时面临sokcet挂起错误。

const response = await axios.get(url)

结果显示,这是因为超时错误,我没有处理错误。

因此,我添加了超时和错误处理,如下面的代码片段所示。

const response = await axios
      .get(url, { timeout: 10000 })
      .catch((error) => {
         if (axios.isAxiosError(error)) {
           const axiosError = error as AxiosError;
           console.log(message, axiosError.message);
           console.log(axiosError.response);
      });

因此,处理错误和指定超时为我解决了套接字挂起的问题。


在我的情况下,问题仅仅是因为返回状态代码102的响应(Processing…)