In diesem Artikel wird der Verbindungsfehler ECONNREFUSED als Beispiel verwendet, um den Prozess der Fehlerbehandlung von Node.js zu veranschaulichen. Angenommen, wir haben den folgenden Code 1. const net = erfordern('net'); 2. net.connect({Port: 9999}) Wenn Port 9999 auf diesem Computer nicht lauscht, erhalten wir die folgende Ausgabe. 1. Ereignisse.js:170 2. throw er; // Nicht behandeltes „Fehler“-Ereignis 3. ^ 4. 5. Fehler: Verbindung ECONNREFUSED 127.0.0.1:9999 6. bei TCPConnectWrap.afterConnect [als oncomplete] (net.js:1088:14) 7. Ausgegebenes „Fehler“-Ereignis bei: 8. bei emitErrorNT (internal/streams/destroy.js:91:8) 9. bei emitErrorAndCloseNT (intern/streams/destroy.js:59:3) 10. bei processTicksAndRejections (internal/process/task_queues.js:81:17) Werfen wir einen kurzen Blick auf den Anrufvorgang von Connect. 1. const req = neues TCPConnectWrap(); 2. req.oncomplete = nach dem Verbinden; 3. req.address = Adresse; 4. erforderlich.port = Port; 5. req.localAddress = lokale Adresse; 6. req.localPort = lokalerPort; 7. // Starten Sie den Drei-Wege-Handshake, um die Verbindung herzustellen. 8. err = self._handle.connect(req, address, port); Als nächstes schauen wir uns die Logik der C++-Schichtverbindung an 1. Fehler = req_wrap->Dispatch(uv_tcp_connect, 2. &wrap->handle_, 3. reinterpret_cast<const sockaddr*>(&addr), 4. Nach dem Verbinden); Die C++-Schicht ruft direkt Libuvs uv_tcp_connect auf und setzt den Rückruf auf AfterConnect. Als nächstes schauen wir uns die Implementierung von libuv an. 1. tun { 2. Fehlernummer = 0; 3. // Nicht blockierender Aufruf 4. r = connect(uv__stream_fd(handle), addr, addrlen); 5. } während (r == -1 && errno == EINTR); 6. // Verbindungsfehler, bestimme den Fehlercode 7. if (r == -1 && errno != 0) { 8. // Immer noch Verbindung, kein Fehler, warte darauf, dass die Verbindung abgeschlossen wird und das Ereignis lesbar wird. 9. if (errno == EINPROGRESS) 10. ; /* kein Fehler */ 11. sonst wenn (errno == ECONNREFUSED) 12. // Verbindung abgelehnt 13. handle->delayed_error = UV__ERR(ECONNREFUSED); 14. sonst 15. return UV__ERR(errno); 16. } 17. uv__req_init(Handle->Loop, req, UV_CONNECT); 18. req->cb = cb; 19. req->handle = (uv_stream_t*) Griff; 20. QUEUE_INIT(&req->Warteschlange); 21. // Zum Handle mounten und auf schreibbares Ereignis warten 22. handle->connect_req = req; 23. uv__io_start(Handle->Loop, &Handle->io_watcher, POLLOUT); Wir sehen, dass Libuv das Betriebssystem asynchron aufruft, dann die Anfrage in den Handle einbindet und sich registriert, um auf schreibbare Ereignisse zu warten. Wenn die Verbindung fehlschlägt, wird der Rückruf uv stream_io ausgeführt. Werfen wir einen Blick auf die Verarbeitung von Libuv (uv stream_io). 1. getsockopt(uv__stream_fd(stream), 2. SOL_SOCKET, 3. SO_ERROR, 4. &Fehler, 5. &Fehlergröße); 6. Fehler = UV__ERR(Fehler); 7. wenn (req->cb) 8. req->cb(req, Fehler); Rufen Sie nach Erhalt der Fehlerinformationen AfterConnect der C++-Ebene zurück. 1. Lokal<Wert> argv[5] = { 2. Integer::Neu(env->isolate(), status), 3. Wrap->Objekt(), 4. req_wrap->Objekt(), 5. Boolean::New(env->isolate(), lesbar), 6. Boolean::New(env->isolate(), beschreibbar) 7. }; 8. 9. req_wrap->MakeCallback(env->oncomplete_string(), arraysize(argv), argv); Rufen Sie dann den Oncomplete-Rückruf der JS-Ebene auf. 1. const ex = Ausnahme mit HostPort (Status, 2. 'verbinden', 3. Anforderungsadresse, 4. req.port, 5. Einzelheiten); 6. wenn (Details) { 7. Beispiel: localAddress = erforderlich.localAddress; 8. zB.localPort = erforderlich.localPort; 9. } 10. // Zerstöre den Sockel 11. selbstzerstören (Beispiel); exceptionWithHostPort erstellt eine Fehlermeldung, zerstört dann den Socket und löst ein Fehlerereignis mit „ex“ als Parameter aus. Sehen wir uns die Implementierung von uvExceptionWithHostPort an. 1. Funktion uvExceptionWithHostPort(err, Systemaufruf, Adresse, Port) { 2. const [ code, uvmsg ] = uvErrmapGet(err) || uvUnmappedError; 3. const-Nachricht = `${syscall} $[code]: ${uvmsg}`; 4. let details = ''; 5. 6. wenn (Port && Port > 0) { 7. Einzelheiten = `${Adresse}:${Port}`; 8. } sonst wenn (Adresse) { 9. Details = ` ${Adresse}`; 10. } 11. const tmpLimit = Fehler.stackTraceLimit; 12. Fehler.stackTraceLimit = 0; 13. const ex = neuer Fehler(`${message}${details}`); 14. Fehler.stackTraceLimit = tmpLimit; 15. Beispielcode = Code; 16. Beispiel: errno = err; 17. Beispiel: syscall = Systemaufruf; 18. Beispiel: Adresse = Adresse; 19. wenn (Hafen) { 20. ex.port = Port; einundzwanzig. } 22. // Informationen zum Aufrufstapel abrufen, aber die aktuell aufgerufene Funktion uvExceptionWithHostPort ausschließen und das Stapelfeld in ex23 einfügen. Error.captureStackTrace(ex, excludedStackFn || uvExceptionWithHostPort); 24. Rückgabe Ex; 25. } Wir sehen, dass Fehlerinformationen hauptsächlich über uvErrmapGet abgerufen werden 1. Funktion uvErrmapGet(Name) { 2. uvBinding = lazyUv(); 3. wenn (!uvBinding.errmap) { 4. uvBinding.errmap = uvBinding.getErrorMap(); 5. } 6. returniere uvBinding.errmap.get(name); 7. } 8. 9. Funktion lazyUv() { 10. wenn (!uvBinding) { 11. uvBinding = internalBinding('uv'); 12. } 13. uvBinding zurückgeben; 14. } Wenn wir weiter nach unten schauen, ruft uvErrmapGet das getErrorMap des uv-Moduls in der C++-Ebene auf. 1. void GetErrMap(const FunctionCallbackInfo<Wert>& args) { 2. Umgebung* env = Umgebung::GetCurrent(args); 3. Isolieren* isolieren = env->isolieren(); 4. Lokaler <Kontext> Kontext = env->Kontext(); 5. 6. Lokal<Map> err_map = Map::Neu(isolier); 7. // Fehlerinformationen von per_process::uv_errors_map abrufen8. size_t errors_len = arraysize(per_process::uv_errors_map); 9. // Aufgabe 10. for (size_t i = 0; i < errors_len; ++i) { 11. // Der Schlüssel der Karte ist der Wert in jedem Element von uv_errors_map und der Wert ist Name und Nachricht 12. const auto& error = per_process::uv_errors_map[i]; 13. Local<Wert> arr[] = {OneByteString(isoliere, fehler.name), 14. OneByteString(isoliere, Fehlernachricht)}; 15. wenn (err_map 16. ->Set(Kontext, 17. Integer::Neu(isolier, Fehler.Wert), 18. Array::Neu(isolieren, arr, Arraygröße(arr))) 19. .IsEmpty()) { 20. Rückkehr; einundzwanzig. } zweiundzwanzig. } dreiundzwanzig. 24. args.GetReturnValue().Set(err_map); 25. } Wir sehen, dass die Fehlerinformationen in per_process::uv_errors_map vorhanden sind. Werfen wir einen Blick auf die Definition von uv_errors_map. 1. Struktur UVError { 2. int-Wert; 3. const char* Name; 4. const char*Nachricht; 5. }; 6. 7. statische const-Struktur UVError uv_errors_map[] = { 8. #define V(name, nachricht) {UV_##name, #name, nachricht}, 9. UV_ERRNO_MAP(V) 10. #undef V 11. }; Das Makro UV_ERRNO_MAP wird wie folgt erweitert: 1. {UV_E2BIG, "E2BIG", "Argumentliste zu lang"}, 2. {UV_EACCES, "EACCES", "Zugriff verweigert"}, 3. {UV_EADDRINUSE, "EADDRINUSE", "Adresse wird bereits verwendet"}, 4. … Das Ergebnis des Exports in die JS-Ebene ist also wie folgt 1. { 2. // Der Schlüssel ist eine von Libuv definierte Zahl, die eigentlich die Definition des Betriebssystems enthält. 3. UV_ECONNREFUSED: ["ECONNREFUSED", "Verbindung abgelehnt"], 4. UV_ECONNRESET: ["ECONNRESET", "Verbindung vom Peer zurückgesetzt"] 5. ... 6. } Node.js fasst diese Informationen schließlich zusammen und gibt sie an den Anrufer zurück. Dies ist die Fehlermeldung, die wir ausgeben. Warum also wird es ECONNREFUSED? Sehen wir uns die Logik des Betriebssystems für diesen Fehlercode an. 1. statisches void tcp_reset(Struktur sock *sk) 2. { 3. Schalter (sk->sk_state) { 4. Fall TCP_SYN_SENT: 5. sk->sk_err = ECONNREFUSED; 6. Pause; 7. // ... 8. } 9. 10. } Wenn das Betriebssystem ein an den Socket gesendetes RST-Paket empfängt, führt es tcp_reset aus. Wir können sehen, dass, wenn der Socket ein Syn-Paket sendet und auf eine Bestätigung wartet, der Fehlercode auf ECONNREFUSED gesetzt wird, wenn ein Fin-Paket empfangen wird. Es ist dieser Fehlercode, den wir ausgeben. Zusammenfassen Dies ist das Ende dieses Artikels über den Fehlerbehandlungsprozessdatensatz von nodejs. Weitere relevante Inhalte zur Fehlerbehandlung von nodejs finden Sie in früheren Artikeln auf 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird! Das könnte Sie auch interessieren:
|
>>: Versuchen Sie Docker+Nginx, um die Single-Page-Anwendungsmethode bereitzustellen
Nach der Installation von Ubuntu 20.04 gibt es st...
Der Code sieht folgendermaßen aus: .Verfahren{ Ra...
Inhaltsverzeichnis 1. Ändern Sie durch Binden des...
Inhaltsverzeichnis Eröffnungsszene Direktes Rende...
1. Wenn die Breite der angrenzenden schwebenden Eb...
Dieser Artikel beschreibt, wie man Redis- und php...
Nachdem der Server, auf dem sich Docker befindet,...
1. Warum maxPostSize festlegen? Der Tomcat-Contai...
Inhaltsverzeichnis Vorwort 1. Docker installieren...
Dieser Artikel ist eine MySQL-Konfigurationsdatei...
1. ip_hash: ip_hash verwendet einen Quelladressen...
Vorwort Im vorherigen Artikel „Detaillierte Erklä...
Inhaltsverzeichnis Einführung in FTP, FTPS und SF...
Vorwort Im Falle eines Primärschlüsselkonflikts o...
<Text> <div id="Wurzel"> &l...