2014-12-09 21 views
5

In Node.js, dovrei usare gli errori per il controllo di flusso, o dovrei li uso più come eccezioni?Best practice NodeJS: errori per il controllo del flusso?

sto scrivendo un controller di autenticazione e di alcuni test di unità in Sails.js, e attualmente, i miei assegni metodo di registrazione per vedere se un utente con lo stesso nome utente esiste. Se un utente è già esistente con il nome utente, il mio metodo modello chiama i suoi argomenti di callback con un nuovo oggetto Error, in questo modo:

Modello:

exists: function (options, cb) { 
    User.findOne({ 
     where: { username: typeof options === 'Object' && options.username ? options.username : options }, 
    }).exec(function (err, user) { 
     if (err) return cb(err); 
     if (user) return cb(new Error("A user with that username already exists.")); 
     cb(null, !!user); 
    }); 
}, 

Controller:

User.exists(req.body.user.username, function (err, exists) { 
    if (err) { 
    console.log("error: ", err); 
    return res.status(409).json({ 
     message: err 
    });  
    } 

    User.create(req.user).then(function (data) { 
    res.status(201).json({ 
     user: data 
    }); 
    }); 
}); 

È questo il migliore pratica? Non sono sicuro che le convenzioni sul nodo favoriscano gli errori per casi eccezionali o per il controllo del flusso. Penso che dovrei riscriverlo, ma voglio conoscere le convenzioni prima di farlo. Penso di aver visto alcuni esempi scritti in questo modo su Sails. Grazie!

+0

Un modo molto più semplice è quello di bandiera 'username' come unico nello schema del modello e utilizzare semplicemente il errore Mongoose ritorna nel tuo controller 'User.create()' per rispondere con un 409. Questo è un approccio più ottimistico perché se l'utente non esiste e se è una richiesta valida, non stai colpendo il DB due volte senza motivo . – srquinn

+0

@jibsales che non ha senso - ma poi, che cosa succede se c'è un errore diverso che richiederebbe una risposta 500?In linguaggi come C#, esistono diversi tipi di eccezioni e puoi controllare quel tipo. So che potrei fare qualcosa del genere su Node se lo volessi, ma è una pratica comune? La decisione che prendo ora influirà sul modo in cui costruisco il resto dell'applicazione. In base al tuo commento, sembra che il nodo utilizzi errori per il controllo del flusso anziché situazioni eccezionali. –

+0

Vedere la mia risposta sotto – srquinn

risposta

2

La risposta di cui sopra è un bene per espresso, ma in controllori Vele non si dovrebbe essere chiamata next; la migliore pratica è di restituire sempre una risposta. Nella maggior parte dei casi, il codice di Sails non vedrà nemmeno next come argomento per una funzione di azione del controller. Inoltre, Sails viene fornito con default response methods incorporato nell'oggetto res, ad esempio res.serverError e res.badRequest, nonché res.negotiate che tenterà di indirizzare l'errore al gestore appropriato per te in base al codice di stato. Così il vostro esempio può essere ottimizzato come:

Modello:

exists: function (options, cb) { 
    User.findOne({ 
     where: { username: typeof options === 'Object' && options.username ? options.username : options }, 
    }).exec(function (err, user) { 
     // res.negotiate will default to a 500 server error 
     if (err) return cb(err); 
     // res.negotiate will just output the status code and error object 
     // as JSON for codes between 400 and 500, unless you 
     // provide a custom view as api/responses/badRequest.ejs 
     if (user) return cb({ 
      status: 409, 
      message: "A user with that username already exists." 
     }); 
     cb(null, !!user); 
    }); 
}, 

Controller:

User.exists(req.body.user.username, function (err, exists) { 
    // Let Sails handle those errors for you 
    if (err) {return res.negotiate(err);} 

    User.create(req.user).then(function (data) { 
    res.status(201).json({ 
     user: data 
    }); 
    }); 
}); 
+1

Contrassegnato correttamente questa risposta - mentre l'altra è valida, specifica Sails. Per la cronaca, ho finito per fare qualcosa di simile, ma ho creato i miei tipi di errore estendendo l'errore, e sto verificando il tipo usando le promesse di Bluebird. –

2

nodo (o Javascript davvero) può generare errori sulle eccezioni utilizzando la parola chiave throw:

if (something_went_wrong) { 
    throw new Error('Doh!'); 
} 

è possibile anche aggiungere ulteriori parametri per l'oggetto Errore di default per dare significato più semantica per i vostri errori nel programma . Detto questo, non si vorrebbe lanciare un errore nel gestore di percorso perché ciò causerebbe il blocco del processo e del server.

Quando si utilizza i gestori di itinerari in Sails (o esprimere in realtà), è sicuramente dovrebbe verificare il tipo di errore e rispondere al client di conseguenza.

// -- Route handler 
app.get('/something', function (req, res, next) { 

    DB.create({ username: 'user' }, function (err, docs) { 

    if (err) { 

     // This checks to see if we have a unique error from MongoDB 
     // and send the appropriate response to the client 
     if (err.code === 11000 || error.code === 11001) { 
     return res.send(409); // or return res.json(409, {message: "User exists"}); 
     } 

     // Any other error type is assumed to be an internal error so we pass it 
     // down the chain to the error handler middleware 
     return next(err); 

    } 

    // This is a client error, not an internal error so we respond to the client 
    // with the appropriate client error type 
    if (docs.length === 0) return res.send(404); 

    if (user.notAuthorized) return res.send(403); 

    res.send('All Good'); 

    }); 

}); 

noti che nel caso in cui il DB risponde con un errore interno, si passa alla funzione next() captata gestendo errore middleware lungo la catena. Qualsiasi middleware con una parentesi di 4 è definito come middleware di gestione degli errori. Sails ha probabilmente qualche gestore di errore di default, ma probabilmente si può anche ignorare che - è necessario controllare i documenti appropriati per queste informazioni come io preferisco il controllo ci guadagno utilizzando espresso solo.

+0

Vedo. Quindi in questo caso, posso usare gli errori per il controllo del flusso, ma ho bisogno di controllare il codice di errore o il tipo o il nome - il che significa che devo capire quali tipi di errori potrebbero essere lanciati da Mongo o Sails. Penso di fare progressi in questa ricerca. –

+0

@ jedd.ahyoung Errori per controllo del flusso nel senso che i valori di err 'indicano che c'è stato un errore. Se * lo si * usi per il controllo del flusso è un problema diverso. Considera inoltre che le librerie promisifying fanno andare le convenzioni sui nodi in favore della semantica di promessa normale. –

+0

@DaveNewton Effettivamente. Sails include [Bluebird] (https://www.npmjs.org/package/bluebird) di default e stavo pensando di usarlo, in realtà, poiché preferisco davvero il modello di promessa. Tuttavia, Bluebird fornisce un metodo 'catch()' per i suoi errori, che (sebbene sia fantastico) significa che devo controllare i nomi e i tipi di errore. –

Problemi correlati