435 Stimmen

NodeJS - Was bedeutet "socket hang up" eigentlich?

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

Es passiert jedes Mal an einem anderen Ort, also manchmal ist es url x, der den Fehler wirft, andere Male ist url x in Ordnung und es handelt sich um eine völlig andere URL:

    Fehler!: Fehler: Socket wurde geschlossen using [zufällige URL einfügen, es ist jedes Mal eine andere]

Fehler: Socket wurde geschlossen
    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 ist sehr schwierig zu debuggen, ich weiß nicht wirklich, wo ich anfangen soll. Um zu beginnen, was IST ein Verbindungsabbruchfehler (Socket hang up error)? Ist es ein 404-Fehler oder ähnliches? Oder bedeutet es einfach, dass der Server eine Verbindung verweigert hat?

Ich kann keine Erklärung dafür finden!

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

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

        if (err) {
            console.log("Ach, ScrapeNexts Fehler!: " + err + " beim Verwenden von " + url);
            errors.nexts.push(url);
        }
        $ = cheerio.load(body);
        // hier wird etwas mit dem '$' Cheerio-Inhalt gemacht
    });
}

Es erfolgt kein direkter Aufruf, um die Verbindung zu schließen, aber ich verwende Node Request, das (soweit ich das beurteilen kann) http.get verwendet, sodass dies nicht erforderlich ist. Bitte korrigiere mich, wenn ich falsch liege!

BEARBEITEN 2: Hier ist ein tatsächliches, im Einsatz befindliches Code-Snippet, das Fehler verursacht. prodURL und andere Variablen sind größtenteils vorher definierte jQuery-Selektoren. Hier wird die async-Bibliothek für Node verwendet.

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

        if (err) {
            console.log("Ach, ScrapeNexts Fehler!: " + err + " beim Verwenden von " + 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);
                }
            ]);
    });
}

289voto

Eye Punkte 8506

Es gibt zwei Fälle, in denen socket hang up ausgelöst wird:

Wenn du ein Client bist

Wenn du als Client eine Anfrage an einen entfernten Server sendest und keine rechtzeitige Antwort erhältst. Dein Socket wird beendet, was diesen Fehler auswirft. Du solltest diesen Fehler abfangen und entscheiden, wie du damit umgehen möchtest: ob du die Anfrage erneut versuchen, für später in die Warteschlange stellen usw.

Wenn du ein Server/Proxy bist

Wenn du als Server, vielleicht ein Proxy-Server, eine Anfrage von einem Client erhältst, dann beginne damit zu arbeiten (oder leite die Anfrage an den Upstream-Server weiter) und bevor du die Antwort vorbereitet hast, entscheidet sich der Client, die Anfrage abzubrechen.

Diese Stack-Trace zeigt, was passiert, wenn ein Client die Anfrage abbricht.

Trace: { [Error: socket hang up] code: 'ECONNRESET' }
    at ClientRequest.proxyError (dein_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 Zeile http.js:1526:9 zeigt auf den gleichen socketCloseListener, den @Blender erwähnt hat, insbesondere:

// Dieser Socket-Fehler trat auf, bevor wir eine Antwort begonnen haben zu empfangen. Der Fehler muss auf der Anfrage ausgelöst werden.
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 Anfrage zum Laden einiger Ressourcen/Seiten dauert lange, und Benutzer aktualisieren einfach die Seite. Diese Aktion führt dazu, dass die vorherige Anfrage abgebrochen wird, was auf deiner Serverseite diesen Fehler auslöst.

Da dieser Fehler auf den Wunsch eines Clients zurückzuführen ist, erwarten sie nicht, eine Fehlermeldung zu erhalten. Daher ist es nicht notwendig, diesen Fehler als kritisch zu betrachten. Ignoriere ihn einfach. Dies wird durch die Tatsache unterstützt, dass bei einem solchen Fehler der res-Socket, auf den dein Client gehört hat, wenn auch noch beschreibbar, zerstört wird.

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

Also, es macht keinen Sinn, irgendwas zu senden, außer den Antwort-Objekt explizit zu schließen:

res.end();

Was du jedoch auf jeden Fall tun solltest, wenn du ein Proxy-Server bist, der die Anfrage bereits an den Upstream weitergeleitet hat, ist, deine interne Anfrage an den Upstream abzubrechen, um dein Desinteresse an der Antwort anzuzeigen, was wiederum dem Upstream-Server signalisiert, eine teure Operation möglicherweise zu stoppen.

66voto

Blender Punkte 273072

Schauen Sie sich die Quelle an:

function socketCloseListener() {
  var socket = this;
  var parser = socket.parser;
  var req = socket._httpMessage;
  debug('HTTP-Socket geschlossen');
  req.emit('close');
  if (req.res && req.res.readable) {
    // Socket wurde geschlossen, bevor wir unten 'end' emittet haben.
    req.res.emit('aborted');
    var res = req.res;
    res.on('end', function() {
      res.emit('close');
    });
    res.push(null);
  } else if (!req.res && !req._hadError) {
    // Dieser Socketfehler trat auf, bevor wir eine Antwort erhalten haben.
    // Der Fehler muss beim Request ausgelöst werden.
    req.emit('error', createHangUpError());
    req._hadError = true;
  }
}

Die Nachricht wird gesendet, wenn der Server nie eine Antwort sendet.

57voto

silentorb Punkte 2282

Ein Fall, der erwähnenswert ist: Wenn ich von Node.js zu Node.js mit Express verbinde, erhalte ich "Verbindungsaufhänge" , wenn ich den angeforderten URL-Pfad nicht mit "/" vorwegnehme.

49voto

Unten ist ein einfaches Beispiel, in dem ich denselben Fehler gemacht habe, als ich vergessen habe, den auskommentierten Code im folgenden Beispiel hinzuzufügen. Das Entkommentieren des Codes req.end() wird dieses Problem lösen.

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

42voto

Aekkawit Chanpen Punkte 511

Ich habe require('http') verwendet, um den https-Dienst zu nutzen, und es zeigte "socket hang up".

Dann habe ich stattdessen require('https') geändert, und es funktioniert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X