NodeJS - Was bedeutet eigentlich "Socket auflegen"?


276

Ich baue mit Node und Cheerio einen Web-Scraper und für eine bestimmte Website erhalte ich den folgenden Fehler (es passiert nur auf dieser einen Website, keine anderen, die ich zu kratzen versuche.

Es passiert jedes Mal an einem anderen Ort, also ist es manchmal url xder Fehler, manchmal url xist es in Ordnung und es ist eine völlig andere 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)

Das Debuggen ist sehr schwierig, ich weiß nicht wirklich, wo ich anfangen soll. Um zu beginnen, was IST eine Steckdose up Fehler hängen? Ist es ein 404-Fehler oder ähnliches? Oder bedeutet das nur, dass der Server eine Verbindung abgelehnt hat?

Ich kann nirgendwo eine Erklärung dafür finden!

BEARBEITEN: Hier ist ein Codebeispiel, das (manchmal) Fehler zurückgibt:

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

Es gibt keinen direkten Anruf, um die Verbindung zu schließen, aber ich verwende, Node Requestwas (soweit ich das beurteilen kann) verwendet, http.getso dass dies nicht erforderlich ist. Korrigieren Sie mich, wenn ich falsch liege!

BEARBEITEN 2: Hier ist ein tatsächlich verwendetes Codebit, das Fehler verursacht. prodURLund andere Variablen sind meistens jquery-Selektoren, die zuvor definiert wurden. Dies verwendet die asyncBibliothek für 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);
                }
            ]);
    });
}

26
Dies bedeutet, dass der Socket endinnerhalb des Zeitlimits kein Verbindungsereignis sendet . Wenn Sie die Anfrage für Cheerio über http.request(nicht http.get) erhalten. Sie müssen anrufen request.end(), um das Senden der Anfrage abzuschließen.
user568109

1
@ user568109 Ich sollte beachten, dass ich den Knotendienst verwende request, keine spezifische http.requestAnfrage (ich denke, ich bin sehr neu im Knoten!). Dies ist die eine: github.com/mikeal/request Dies scheint die Anfrage automatisch zu beenden, nein? EDIT: Laut den Dokumenten ist http method, defaults to GETdas also nicht das Problem.
JVG

2
Dann sollte es nicht das Problem sein. Was passiert, wenn Sie den Scraping-Teil einschließlich cheerio.load auskommentieren und denselben Inhalt zurückgeben? Der Haken hier ist, cheerio.loadist asynchron. Es kann also sein, dass es nicht fertig ist, bevor Sie anfangen, Dinge mit $ zu tun.
user568109

4
Ich habe auch manchmal festgestellt, dass wenn ich eine Site zu aggressiv crawle (wie mehr als 10 gleichzeitige Verbindungen), sie mit Socket-Aufhängen reagieren, also könnte es auch so sein.
tobek

1
Nur zu Ihrer Information hang upbedeutet auf Englisch, ein elektronisches Gespräch zu beenden, indem die Verbindung unterbrochen wird. entstand aus dem Auflegen des altmodischen Telefons.
12онстантин Ван

Antworten:


161

Es gibt zwei Fälle, in denen socket hang upgeworfen wird:

Wenn Sie ein Kunde sind

Wenn Sie als Client eine Anfrage an einen Remote-Server senden und keine rechtzeitige Antwort erhalten. Ihr Socket ist beendet, was diesen Fehler auslöst. Sie sollten diesen Fehler abfangen und entscheiden, wie er behandelt werden soll: ob Sie die Anforderung erneut versuchen, sie für später in die Warteschlange stellen usw.

Wenn Sie ein Server / Proxy sind

Wenn Sie als Server, möglicherweise als Proxyserver, eine Anforderung von einem Client erhalten und dann darauf reagieren (oder die Anforderung an den Upstream-Server weiterleiten), und bevor Sie die Antwort vorbereitet haben, beschließt der Client, abzubrechen / abzubrechen die Anfrage.

Diese Stapelverfolgung zeigt, was passiert, wenn ein Client die Anforderung abbricht.

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)

Die Linie http.js:1526:9zeigt auf das socketCloseListeneroben von @Blender erwähnte, insbesondere:

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

Dies ist ein typischer Fall, wenn der Client ein Benutzer im Browser ist. Die Anforderung zum Laden einer Ressource / Seite dauert lange, und Benutzer aktualisieren die Seite einfach. Eine solche Aktion führt dazu, dass die vorherige Anforderung abgebrochen wird, was auf Ihrer Serverseite diesen Fehler auslöst.

Da dieser Fehler durch den Wunsch eines Kunden verursacht wird, erwarten sie keine Fehlermeldung. Sie müssen diesen Fehler also nicht als kritisch betrachten. Ignoriere es einfach. Dies wird durch die Tatsache gefördert, dass bei einem solchen Fehler der resSocket, den Ihr Client gehört hat, zerstört wird, obwohl er noch beschreibbar ist.

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

Es macht also keinen Sinn, etwas zu senden, außer das Antwortobjekt explizit zu schließen:

res.end();

Aber was Sie tun sollten , sicher , wenn Sie sind ein Proxy - Server , die bereits die Anforderung an den Upstream weitergeleitet hat, ist zu Abbruch Ihrer internen Anforderung an den Upstream, Ihr Mangel an Interesse an der Antwort , die anzeigt, was wiederum den Upstream sagen Server, um möglicherweise einen teuren Vorgang zu stoppen.


2
Wie kann ich als Kunde die Anfrage einfach länger warten lassen? Es ist nach 35 Sekunden fehlerhaft und ich brauche es, um ungefähr eine Minute zu warten.
Big Money

Ich stehe vor dem gleichen Problem. Ist es möglich, auf eine Antwort zu warten und die nächste Anfrage nacheinander zu senden. Kann ich wissen, wie ich mit diesem Socket umgehen soll?
Deepak

@ BigMoney könnten Sie verwenden setTimeout(). siehe diese Frage: stackoverflow.com/questions/6214902/…
die Holla

Ihre Daten haben mich aus der Hölle überlebt, ich habe node.js als Proxyserver zwischen Upstream-Server und Client verwendet. Timeout auf Anfrage hat diesen Fehler ausgelöst, nur weil ich vergessen habe, ihn zu verwenden res.send, danke
Farzad YZ

Sie können als Client "Socket Hang Up" erhalten, wenn Sie versuchen, über dieselbe Verbindung eine zweite Anforderung an den Entwicklungswebserver eines Django zu senden. Es wird nicht unterstützt keep-alive. Und falls Ihr Kunde dies erwartet, erhalten Sie den Fehler. Es sieht folgendermaßen aus .
X-Yuri

53

Schauen Sie sich die Quelle an :

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

Die Nachricht wird ausgegeben, wenn der Server niemals eine Antwort sendet.


2
Können Sie aus funktionaler Sicht erklären, was dies bedeutet? Ich versuche hier Schutzmaßnahmen zu erstellen, indem ich die fehlerhaften URLs zu einem Array hinzufüge und sie später abkratzt. Ich habe an einigen Stellen gelesen, dass die Fehler möglicherweise ein Problem mit Node in der Warteschlange darstellen. Ich weiß nicht, wie ich dies am besten beheben und vermeiden kann.
JVG

5
Aber wie lange wartet es?
CommaToast

2
Es sollte en.wikipedia.org/wiki/Exponential_backoff für die Implementierung von "wie lange" verwenden.
Norman H

Dieses "Auflegen der Steckdose" ist bedeutungslos. Dies ist nur eine Überraschung von NodeJS Team.
Puchu

45

Ein erwähnenswerter Fall: Wenn ich mit Express eine Verbindung von Node.js zu Node.js herstelle, wird "Socket auflegen" angezeigt, wenn dem angeforderten URL-Pfad nicht "/" vorangestellt wird.


1
das war mein problem, sowohl client als auch server in rein http node.js
ashley willis

1
@silentorb: Kannst du bitte Beispiel-URL zeigen? Ich habe in diesem Fall den gleichen Fehler. Danke.
Pritam

4
Fehler: "Benutzer / Login", Erfolg: "/ Benutzer / Login"
Silentorb

4
Mann, ich habe fast eine Stunde damit verbracht, es zu debuggen! Sah deine Antwort und dachte SH **, fügte das / hinzu und es funktioniert gut :) danke!
Daniel Gruszczyk

4
Sie haben mir mit dieser Antwort Stunden gespart!
Imhotep

32

Ich habe require('http')den https- Dienst verwendet und er zeigte " socket hang up".

Dann habe ich mich verändert require('http') zu require('https')statt, und es funktioniert.


Dies ist zwar eine Lösung für das Problem, aber keine Antwort auf die Frage. Das Poster wollte eine Antwort auf die Bedeutung der Fehlermeldung. Darüber hinaus gibt es bereits viele qualitativ hochwertige Antworten. Ihre bietet keinen zusätzlichen Wert.
Johannes Dorn

19
Danke für deinen Kommentar. Ich verschwende meine Zeit für diesen Fehler. Schließlich versuche ich einfach diese Lösung und es funktioniert. Ich will nur teilen. Ich hoffe, es ist nützlich für andere, ihre Zeit nicht zu verschwenden und nicht als qualitativ hochwertige Antwort zu loben.
Aekkawit Chanpen

12
@JohannesDorn Dies ist eine implizite Antwort auf die Frage, was der Fehler bedeutet. Und eine nützliche dazu.
Ulad Kasach

29

Unten ist ein einfaches Beispiel, bei dem ich den gleichen Fehler erhalten habe, als ich den kommentierten Code im folgenden Beispiel nicht hinzugefügt habe. Wenn Sie den Code req.end()nicht kommentieren, wird dieses Problem behoben .

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
Das hat meine geistige Gesundheit gerettet ... Danke!
PGallagher

Du bist ein Held! Danke dir.
Xenhat

17

Wenn man die Antwort von Blender erweitert, geschieht dies in einer Reihe von Situationen. Die häufigsten, denen ich begegne, sind:

  1. Der Server ist abgestürzt.
  2. Der Server hat Ihre Verbindung abgelehnt, höchstwahrscheinlich blockiert durch User-Agent.

socketCloseListenerWie in Blenders Antwort dargelegt, ist dies nicht der einzige Ort, an dem Aufhängefehler auftreten.

Zum Beispiel hier zu finden :

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

Sie können es curlmit den Headern und solchen versuchen , die vom Knoten gesendet werden, und sehen, ob Sie dort eine Antwort erhalten. Wenn Sie keine Antwort mit erhalten curl, aber eine Antwort in Ihrem Browser erhalten, wird Ihr User-AgentHeader höchstwahrscheinlich blockiert.


3
Ein weiterer Grund, warum der Server Ihre Verbindung ablehnen könnte (ich habe dies nur beim Wechsel zu prod anstelle von QA getroffen), ist, wenn Ihr Server eine https-Anfrage anstelle von http erwartet.
Mcole

7

Ein weiterer erwähnenswerter Fall (für Linux und OS X) ist, dass Sie, wenn Sie eine Bibliothek wie httpszum Ausführen der Anforderungen verwenden oder wenn Sie https://...als URL der lokal bereitgestellten Instanz übergeben, den Port verwenden, 443der ein reservierter privater Port ist, und Sie könnte in Socket hang upoder ECONNREFUSEDFehler enden .

Verwenden Sie stattdessen port 3000, fe und führen Sie eine httpAnfrage aus.


6

Ich hatte das gleiche Problem bei der Verwendung der Nano- Bibliothek zum Herstellen einer Verbindung mit Couch DB . Ich habe versucht, das Verbindungspooling mithilfe der Keepaliveagent- Bibliothek zu optimieren, und es ist immer wieder mit einer Socket-Auflegen- Nachricht fehlgeschlagen .

var KeepAliveAgent = require('agentkeepalive');

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

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

Nach einigen Kämpfen konnte ich das Problem lösen - als es herauskam, war es ein sehr, sehr einfacher Fehler. Ich habe über das HTTPS-Protokoll eine Verbindung zur Datenbank hergestellt, aber immer wieder einen Keepalive-Agenten an mein Nano-Objekt übergeben, der als Beispiel für die Verwendung dieser Bibliothek erstellt wurde (sie basieren auf einigen Standardeinstellungen, die http verwenden).

Eine einfache Änderung zur Verwendung von HttpsAgent hat den Trick gemacht:

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

1
Wenn die Anforderung für Port 443 konfiguriert ist und die Anforderung über das http-Modul und nicht über das https-Modul ausgegeben wird, wird ein Socket aufgelegt. Es wäre schön, wenn es mehr Details darüber gäbe, warum die Trennung stattgefunden hat (SSL / TLS-Aushandlung?). Ich habe diese Detailstufe zum Beispiel in ASP.NET gesehen.
Richard Collette

6

Dies verursachte mir Probleme, da ich alles hier Aufgeführte, aber immer noch Fehler bekam. Es stellt sich heraus, dass der Aufruf von req.abort () tatsächlich einen Fehler mit dem Code ECONNRESET auslöst, sodass Sie diesen tatsächlich in Ihrem Fehlerbehandler abfangen müssen.

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

5

Für requestModulbenutzer

Zeitüberschreitungen

Es gibt zwei Haupttypen von Zeitüberschreitungen: Verbindungszeitüberschreitungen und Lesezeitüberschreitungen . Ein Verbindungszeitlimit tritt auf, wenn das Zeitlimit erreicht wird, während Ihr Client versucht, eine Verbindung zu einem Remotecomputer herzustellen (entsprechend dem connect()Anruf am Socket). Ein Lesezeitlimit tritt immer dann auf, wenn der Server zu langsam ist, um einen Teil der Antwort zurückzusenden.

Beachten Sie, dass Verbindungszeitüberschreitungen einen ETIMEDOUTFehler ausgeben und Zeitüberschreitungen lesen einen ECONNRESETFehler ausgeben .


3

Ich hatte das gleiche Problem bei der Anfrage an einen Server. In meinem Fall hat es mir geholfen, in den Kopfzeilen der Anforderungsoptionen einen Wert auf User-Agent festzulegen.

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

Dies ist kein allgemeiner Fall und hängt von den Servereinstellungen ab.


2

Der Grund kann auch darin liegen, dass anstelle von from eine appInstanz expressverwendet wirdserverconst server = http.createServer(app) , während Server - Socket zu schaffen.

Falsch

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

Richtig

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

1

Ich mache sowohl Web- (Knoten) als auch Android-Entwicklung und öffne Android Studio-Gerätesimulator und Docker zusammen. Beide verwenden Port 8601, es klagte socket hang upFehler, nachdem ich Android Studio-Gerätesimulator geschlossen habe und es funktioniert gut auf der Knotenseite. Verwenden Sie Android Studio-Gerätesimulator und Docker nicht zusammen.


1

Ich habe einen ähnlichen Fehler bei der Verwendung von CouchDB im OCP-Cluster erhalten.

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

Welches sollte "http" sein, nicht "https", um eine Verbindung mit meiner CouchDB-Instanz herzustellen. Ich hoffe, es könnte für jeden hilfreich sein, der mit einem ähnlichen Problem konfrontiert ist.


0

In meinem Fall lag dies daran, dass eine Application / JSON-Antwort schlecht formatiert war (enthält einen Stack-Trace). Die Antwort wurde nie an den Server gesendet. Das Debuggen war sehr schwierig, da es kein Protokoll gab. Dieser Thread hilft mir sehr zu verstehen, was passiert.



0

Ich bin gestern auf dieses Problem gestoßen, als ich meine Webanwendung und meinen node.js-Server über IntelliJ IDEA 2016.3.6 ausgeführt habe. Ich musste lediglich meine Cookies und meinen Cache in meinem Chrome-Browser löschen.


0

Wenn dieser Fehler über eine https-Verbindung auftritt und sofort auftritt, kann dies ein Problem beim Einrichten der SSL-Verbindung sein.

Für mich war es dieses Problem https://github.com/nodejs/node/issues/9845, aber für Sie könnte es etwas anderes sein. Wenn es ein Problem mit der SSL gibt, sollten Sie es mit dem Paket nodejs tls / ssl reproduzieren können, das nur versucht, eine Verbindung zur Domäne herzustellen


0

Ich denke, es ist erwähnenswert ...

Ich habe Tests für Google APIs erstellt. Ich habe die Anfrage mit einem provisorischen Server abgefangen und diese dann an die echte API weitergeleitet. Ich habe versucht, nur die Header in der Anfrage weiterzugeben, aber einige Header verursachten ein Problem mit Express am anderen Ende.

Ich musste nämlich ,, und Header löschen connection, bevor ich das Anforderungsmodul zum Weiterleiten verwendete.acceptcontent-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.
})

0

In meinem Fall war es kein Fehler, sondern erwartetes Verhalten für Chrome-Browser. Chrome hält die Verbindung aufrecht (aus Gründen der Geschwindigkeit, denke ich), aber der Server von node.js stoppt sie nach 2 Minuten und Sie erhalten eine Fehlermeldung.

Wenn Sie versuchen, eine GET-Anfrage mit dem Edge-Browser zu stellen, tritt überhaupt kein Fehler auf. Wenn Sie das Chromfenster schließen, wird sofort eine Fehlermeldung angezeigt.

Was tun? 1) Sie können diese Fehler filtern, da es sich nicht wirklich um Fehler handelt. 2) Vielleicht gibt es eine bessere Lösung :)


0

Hier scheint es einen weiteren Fall zu geben, nämlich, dass Electron kein Fan des Domainnamens "localhost" ist. In meinem Fall musste ich Folgendes ändern:

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

dazu:

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

Danach ging das Problem einfach weg.

Dies bedeutet, dass die DNS-Auflösung (lokal oder remote) möglicherweise ebenfalls Probleme verursacht.


0

Nach einem langen debug in den Knoten js Code, mongodb Verbindungszeichenfolge, CORS etc Überprüfung, für mich zu einer anderen Portnummer nur Schale server.listen(port);machte es Arbeit, in postman, versuchen Sie das auch. Keine Änderungen an den proxyEinstellungen, nur die Standardeinstellungen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.