359

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

没有直接调用来关闭连接,但我正在使用Node Requestwhich(据我所知)使用http.get,所以这不是必需的,如果我错了,请纠正我!

编辑 2:这是一个实际的、正在使用的代码,它会导致错误。prodURL而其他变量大多是前面定义的jquery选择器。这使用了Node.js 的async库。

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);
                }
            ]);
    });
}
4

30 回答 30

228

socket hang up被抛出有两种情况:

当你是客户

当您作为客户端向远程服务器发送请求,但没有收到及时响应时。您的套接字已结束,这会引发此错误。您应该捕获此错误并决定如何处理它:是否重试请求,将其排队以备后用等。

当您是服务器/代理时

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

此堆栈跟踪显示客户端取消请求时会发生什么。

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)

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

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

但是,如果您是已经将请求中继到上游的代理服务器,您应该做的是中止您对上游的内部请求,表明您对响应缺乏兴趣,这反过来会告诉上游服务器可能会停止昂贵的操作。

于 2015-01-08T07:37:30.423 回答
60

看看源代码

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

当服务器从不发送响应时发出消息。

于 2013-06-08T01:51:38.403 回答
51

一个值得一提的案例:当使用 Express 从 Node.js 连接到 Node.js 时,如果我没有在请求的 URL 路径前加上“/”前缀,我会得到“socket hang up”。

于 2014-05-13T17:08:34.560 回答
45

下面是一个简单的例子,当我错过在下面的例子中添加注释代码时,我得到了同样的错误。取消注释代码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();
于 2018-02-09T23:58:57.660 回答
40

我曾经require('http')使用过https服务,它显示“ socket hang up”。

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

于 2017-04-04T08:42:02.277 回答
21

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

  1. 服务器崩溃了。
  2. 服务器拒绝了您的连接,很可能被User-Agent.

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标头很可能被阻止了。

于 2013-06-08T15:41:39.043 回答
8

另一个值得一提的情况(对于 Linux 和 OS X)是,如果您使用类似于https执行请求的库,或者如果您https://...作为本地服务实例的 URL 传递,您将使用443作为保留的私有端口的端口,并且您Socket hang up可能会以ECONNREFUSED错误告终。

相反,请使用 port 3000、 fe 并执行http请求。

于 2016-02-16T13:00:37.227 回答
6

我在使用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 的默认值)。

使用HttpsAgent的一项简单更改就成功了:

var KeepAliveAgent = require('agentkeepalive').HttpsAgent;
于 2015-03-20T09:34:54.583 回答
6

对于request模块用户

超时

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

请注意,连接超时会发出ETIMEDOUT错误,而读取超时会发出ECONNRESET错误。

于 2018-02-12T21:47:37.290 回答
6

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

req.on('error', function(err) {
    if (err.code === "ECONNRESET") {
        console.log("Timeout occurs");
        return;
    }
    //handle normal errors
});
于 2018-06-12T15:53:28.417 回答
5

在向某些服务器请求期间,我遇到了同样的问题。就我而言,在请求选项的标头中将任何值设置为 User-Agent 对我有帮助。

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

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

于 2017-08-05T13:15:30.043 回答
3

也可能是因为在创建服务器套接字时使用了appinstance ofexpress而不是serverfrom 。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);
});
于 2018-03-13T19:45:08.287 回答
2

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

req.setTimeout([your needed timeout])

在路由器上。

于 2020-10-01T06:01:58.837 回答
2

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

在我的例子中,我发送了一个负载超过 20K 的请求。这被服务器拒绝了。我通过删除文本并重试直到请求成功来验证这一点。在确定最大可接受长度后,我验证添加单个字符会导致错误出现。我还通过从 Python 应用程序和 Postman 发送相同的请求来确认客户端不是问题。所以无论如何,我相信,就我而言,有效载荷的长度是我的具体问题。

再一次,问题的根源是轶事。一般问题是“服务器说不”。

于 2020-07-08T12:56:29.087 回答
1

在 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 实例。希望对遇到类似问题的人有所帮助。

于 2020-05-26T11:07:21.323 回答
1

使用 时也会发生此错误http.request,可能您的请求尚未完成。

例子:

const req = https.request(options, res => {})

而且您总是需要添加这一行:req.end() 使用此功能,我们将命令完成发送请求。

正如文档中所说:

使用 http.request() 必须始终调用 req.end() 来表示请求的结束——即使没有数据写入请求正文。

于 2020-06-23T21:08:27.293 回答
1

我同时做web(节点)和Android开发,同时打开Android Studio设备模拟器和docker,它们都使用端口8601,它抱怨socket hang up错误,关闭Android Studio设备模拟器后它在节点端运行良好。不要同时使用 Android Studio 设备模拟器和 docker。

于 2017-10-06T22:07:35.387 回答
1

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

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

对此:

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

之后问题就消失了。

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

于 2020-02-24T22:55:25.717 回答
0

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

为了解决问题,同样在此链接中,只需在 express.bodyParser() 之前在 express 路由中声明 API 路由(用于代理)。

于 2017-02-25T00:08:09.283 回答
0

Got "[GET] localhost:4200, Socket hang up" during Azure Static Web App (SWA) Emulator for Angular app.

Solution is to remove this from angular.json:

"headers": {"cross-origin-opener-policy": "same-origin-allow-popups"}
于 2022-03-03T22:43:47.773 回答
0

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

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

于 2017-12-11T04:12:36.470 回答
0

我觉得值得注意...

我正在为 Google API 创建测试。我正在使用临时服务器拦截请求,然后将它们转发到真正的 api。我试图只传递请求中的标头,但是一些标头导致另一端的 express 出现问题。

也就是说,在使用请求模块转发之前,我必须删除connectionaccept和标头。content-length

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.
})
于 2018-02-08T20:38:00.193 回答
0

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

绝对是一个耗时的错误!

于 2022-01-11T10:00:28.397 回答
0

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

var nano = require('nano')('http://localhost:5984');
var db = nano.use('address');
var app = express();
于 2020-09-30T14:35:06.847 回答
0

就我而言,这是因为 application/json 响应格式错误(包含堆栈跟踪)。响应从未发送到服务器。调试起来非常棘手,因为没有日志。这个线程帮助我理解发生了什么。

于 2017-01-03T07:39:47.377 回答
0

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

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

于 2021-09-14T03:00:06.613 回答
0

在对节点 js 代码、mongodb 连接字符串、检查 CORS 等进行长时间调试后,对我来说,只需切换到不同的端口号server.listen(port);就可以了,进入postman,也试试。没有更改proxy设置,只是默认值。

于 2020-06-06T08:26:36.190 回答
0

我的情况不是错误,而是 chrome 浏览器的预期行为。Chrome 保持 tls 连接处于活动状态(我认为是为了提高速度),但 node.js 服务器在 2 分钟后停止它,你会收到一个错误。

如果您使用边缘浏览器尝试 GET 请求,则根本不会出错。如果您要关闭 chrome 窗口 - 您将立即收到错误消息。

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

于 2019-01-03T13:35:29.267 回答
0

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

于 2021-06-03T17:50:57.970 回答
0

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

于 2017-05-05T15:15:30.953 回答