Errore nella gestione dei principi per le applicazioni Node.js + Express.js?


177

Sembra che la segnalazione / la gestione degli errori avvenga in modo diverso nelle applicazioni Node.js + Express.js rispetto ad altri framework. Ho ragione nel capire che funziona come segue?

A) Rileva errori ricevendoli come parametri per le tue funzioni di callback. Per esempio:

doSomethingAndRunCallback(function(err) { 
    if(err) {  }
});

B) Segnalare errori nel MIDDLEWARE chiamando next (err). Esempio:

handleRequest(req, res, next) {
    // An error occurs…
    next(err);
}

C) Segnala errori in ROUTES lanciando l'errore. Esempio:

app.get('/home', function(req, res) {
    // An error occurs
    throw err;
});

D) Gestire gli errori configurando il proprio gestore degli errori tramite app.error () o utilizzare il gestore degli errori Connect generico. Esempio:

app.error(function(err, req, res, next) {
    console.error(err);
    res.send('Fail Whale, yo.');
});

Questi quattro principi sono alla base di tutti gli errori di gestione / segnalazione nelle applicazioni Node.js + Express.js?

Risposte:


183

La gestione degli errori in Node.js è generalmente del formato A). La maggior parte dei callback restituisce un oggetto errore come primo argomento o null.

Express.js utilizza il middleware e la sintassi del middleware utilizza B) ed E) (menzionato di seguito).

C) è una cattiva pratica se me lo chiedi.

app.get('/home', function(req, res) {
    // An error occurs
    throw err;
});

Puoi facilmente riscrivere quanto sopra come

app.get('/home', function(req, res, next) {
    // An error occurs
    next(err);
});

La sintassi del middleware è valida in una getrichiesta.

Per quanto riguarda D)

(07:26:37 PM) tjholowaychuk: app.error viene rimosso in 3.x

TJ ha appena confermato che app.errorè deprecato a favore di E

E)

app.use(function(err, req, res, next) {
  // Only handle `next(err)` calls
});

Qualsiasi middleware che ha una lunghezza di 4 (4 argomenti) è considerato middleware di errore. Quando una chiamata si next(err)connette, il middleware basato su errori viene chiamato.


11
Grazie! Per chiunque possa trovarlo in futuro, sembra che l'ordine dei parametri per "metodo e" sia in realtà err, req, res, next (invece di req, res, next, err).
Clint Harris,

9
Quindi questo sembra fantastico, ma un problema che sto vedendo è che alcuni errori non arrivano mai ai gestori degli errori che descrivi e possono essere catturati solo da un gestore process.on ('uncaughtException', fn). La saggezza convenzionale è quella di lasciare che ciò accada e fare affidamento su Forever o simili per riavviare l'app, ma se lo fai, come restituisci una pagina di errore amichevole?
Paul,

1
@chovy Inoltre, solo un amico. Il gestore degli errori deve essere assegnato all'app dopo l'errore generato / successivo. Se è precedente, non verrà rilevato l'errore.
Lee Olayvar,

3
next (err) è essenzialmente la versione Express di lanciare un errore, ma devi chiamarlo esplicitamente nel tuo middleware
qodeninja,

1
@qodeninja Questo metodo è considerato una buona pratica in Express.
David Oliveros,


3

Perché primo parametro?

A causa della natura asincrona di Node.js, il modello first-parameter-as-err è diventato ben definito come convenzione per la gestione degli errori Node.js dell'utente . Questo perché asincrono:

try {
    setTimeout(function() {
        throw 'something broke' //Some random error
    }, 5)
}
catch(e) {
   //Will never get caught
}

Quindi, invece, avere il primo argomento del callback è praticamente l'unico modo sensato per passare gli errori in modo asincrono oltre a lanciarli.

unhandled exceptionCiò comporterà un risultato che, proprio nel modo in cui suona, implica che non è stato fatto nulla per far uscire l'applicazione dal suo stato confuso.

Eccezioni, perché esistono?

Vale la pena notare, tuttavia, che praticamente tutte le parti di Node.js sono emittenti di eventi e il lancio di un'eccezione è un evento di basso livello che può essere gestito come tutti gli eventi:

//This won't immediately crash if connection fails
var socket = require("net").createConnection(5000);
socket.on("error", function(err) {
    console.error("calm down...", err)
});

Questo può-ma-non dovrebbe essere portato all'estremo per catturare tutti gli errori e creare un'applicazione che farà di tutto per non andare in crash. Questa è un'idea terribile in quasi tutti i casi d'uso, perché lascerà lo sviluppatore senza alcuna idea di cosa stia succedendo nello stato dell'applicazione ed è analogo al wrapping di main in try-catch.

Domini: raggruppamento logico degli eventi

Come parte della gestione di questo problema di eccezioni che fanno cadere le applicazioni, i domini consentono allo sviluppatore di prendere, ad esempio l'applicazione Express.js, e provare a chiudere le connessioni in modo ragionevole in caso di guasto catastrofico.

ES6

Probabilmente sta menzionando che questo cambierà di nuovo poiché ES6 consente al modello di generatore di creare eventi asincroni che sono ancora raggiungibili con blocchi try / catch.

Koa (scritto da TJ Holowaychuck, stesso autore originale di Express.js) lo fa chiaramente. Utilizza l' yieldistruzione ES6 per creare blocchi che, sebbene appaiano quasi sincroni, vengono gestiti nel solito modo asincrono del nodo:

app.use(function *(next) {
    try {
        yield next;
    } 
    catch (err) {
        this.status = err.status || 500;
        this.body = err.message;
        this.app.emit('error', err, this);
    }
});

app.use(function *(next) {
    throw new Error('some error');
})

Questo esempio è stato sottratto senza vergogna da qui .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.