Lorsque j'ai commencé à travailler avec Express et essayé de comprendre comment gérer les erreurs, j'ai eu du mal. Il y avait le sentiment que personne n'avait écrit sur ce dont j'avais besoin. En conséquence, j'ai dû chercher moi-même des réponses à mes questions. Aujourd'hui, je veux dire tout ce que je sais sur la gestion des erreurs dans les applications Express. Commençons par les erreurs synchrones.

Gestion des erreurs synchrones
Si vous devez gérer une erreur synchrone, vous pouvez tout d'abord, à l'aide de l'instruction
throw
,
throw
une telle erreur dans le gestionnaire de requêtes Express. Veuillez noter que les gestionnaires de demandes sont également appelés «contrôleurs», mais je préfère utiliser le terme «gestionnaire de demandes» comme il me semble plus clairement.
Voici à quoi ça ressemble:
app.post('/testing', (req, res) => { throw new Error('Something broke! ') })
Ces erreurs peuvent être détectées à l'aide du gestionnaire d'erreurs Express. Si vous n'avez pas écrit votre propre gestionnaire d'erreurs (nous en parlerons plus loin ci-dessous), Express traitera l'erreur en utilisant le gestionnaire par défaut.
Voici ce que fait le gestionnaire d'erreurs Express standard:
- Définit le code d'état de réponse HTTP sur 500.
- Envoie une réponse textuelle à l'entité exécutant la demande.
- Enregistre une réponse textuelle dans la console.
Message d'erreur affiché dans la consoleGestion des erreurs asynchrones
Pour gérer les erreurs asynchrones, vous devez envoyer une erreur au gestionnaire d'erreurs Express via l'argument
next
:
app.post('/testing', async (req, res, next) => { return next(new Error('Something broke again! ')) })
C'est ce qui arrive à la console lors de la journalisation de cette erreur.
Message d'erreur affiché dans la consoleSi vous utilisez la construction async / wait dans une application Express, vous devrez utiliser une fonction wrapper comme
express-async-handler . Cela vous permet d'écrire du code asynchrone sans blocs
try / catch . En savoir plus sur async / wait dans Express
ici .
const asyncHandler = require('express-async-handler') app.post('/testing', asyncHandler(async (req, res, next) => {
Une fois que le gestionnaire de requêtes est encapsulé dans
express-async-handler
, vous pouvez, comme décrit ci-dessus, générer une erreur à l'aide de l'instruction
throw
. Cette erreur ira au gestionnaire d'erreurs Express.
app.post('/testing', asyncHandler(async (req, res, next) => { throw new Error('Something broke yet again! ') }))
Message d'erreur affiché dans la consoleÉcrire votre propre gestionnaire d'erreurs
Les gestionnaires d'erreur express prennent 4 arguments:
- erreur
- req
- res
- suivant
Vous devez les placer après les gestionnaires et les itinéraires intermédiaires.
app.use() app.get() app.post() app.put() app.delete()
Si vous créez votre propre gestionnaire d'erreurs, Express cessera d'utiliser le gestionnaire d'erreurs standard. Pour gérer l'erreur, vous devez générer une réponse pour l'application frontale qui a adressé le point de terminaison auquel l'erreur s'est produite. Cela signifie que vous devez effectuer les opérations suivantes:
- Générez et envoyez un code d'état de réponse approprié.
- Formez et envoyez une réponse appropriée.
Le code d'état approprié dans chaque cas particulier dépend de ce qui s'est exactement passé. Voici une liste des erreurs courantes que vous devez être prêt à gérer:
- Erreur
400 Bad Request
. Utilisé dans deux situations. Premièrement, lorsque l'utilisateur n'a pas inclus le champ obligatoire dans la demande (par exemple, le champ avec les informations de carte de crédit n'a pas été rempli dans le formulaire de paiement envoyé). Deuxièmement, lorsque la demande contient des données incorrectes (par exemple, entrer différents mots de passe dans le champ de mot de passe et dans le champ de confirmation de mot de passe). - Erreur
401 Unauthorized
. Ce code d'état de réponse est appliqué si l'utilisateur a entré des informations d'identification incorrectes (telles que nom d'utilisateur, adresse e-mail ou mot de passe). - Erreur
403 Forbidden
. Utilisé lorsque l'utilisateur n'est pas autorisé à accéder au point de terminaison. - Erreur
404 Not Found
. Il est utilisé dans les cas où le point final ne peut pas être détecté. - Erreur
500 Internal Server Error
Erreur de 500 Internal Server Error
. Il est appliqué lorsque la demande envoyée par le serveur frontal est correctement formée, mais une erreur s'est produite sur le serveur principal.
Une fois le code d'état de réponse approprié défini, il doit être défini à l'aide de
res.status
:
app.use((error, req, res, next) => {
Le code d'état de réponse doit correspondre au message d'erreur. Pour ce faire, envoyez le code d'état avec l'erreur.
La façon la plus simple de le faire est d'utiliser le package
http-errors . Il permet d'envoyer trois informations par erreur:
- Le code d'état de réponse.
- Le message associé à l'erreur.
- Toutes les données qui doivent être envoyées (ceci est facultatif).
Voici comment installer le package
http-errors
:
npm install http-errors --save
Voici comment utiliser ce package:
const createError = require('http-errors')
Prenons un exemple qui vous permettra de bien comprendre tout cela.
Imaginez que nous essayons de trouver un utilisateur à son adresse e-mail. Mais cet utilisateur est introuvable. En conséquence, nous décidons d'envoyer une erreur
User not found
en réponse à la demande correspondante, informant l'appelant que l'utilisateur n'a pas été trouvé.
Voici ce que nous devrons faire lors de la création de l'erreur:
- Définissez le code d'état de réponse sur
400 Bad Request
(après tout, l'utilisateur a entré des données incorrectes). Ce sera notre premier paramètre. - Envoyez un message à l'appelant comme
User not found
. Ce sera le deuxième paramètre.
app.put('/testing', asyncHandler(async (req, res) => { const { email } = req.body const user = await User.findOne({ email })
Vous pouvez obtenir le code d'état à l'aide de la construction
error.status
et le message d'erreur à l'aide de
error.message
:
Le résultat des erreurs de journalisation dans la consoleEnsuite, l'état de réponse est défini à l'aide de
res.status
et le message est écrit dans
res.json
:
app.use((error, req, res, next) => {
Personnellement, je préfère envoyer un code d'état, un message et un résultat de trace de pile dans de telles réponses. Cela facilite le débogage.
app.use((error, req, res, next) => {
▍ Code d'état de réponse par défaut
Si la source de l'erreur n'est pas
createError
, elle n'aura pas la propriété
status
. Voici un exemple dans lequel une tentative de lecture d'un fichier inexistant a été effectuée à l'aide de
fs.readFile
:
const fs = require('fs') const util = require('util')
Un tel objet d'erreur n'aura pas la propriété
status
:
app.use((error, req, res, next) => { console.log('Error status: ', error.status) console.log('Message: ', error.message) })
Le résultat des erreurs de journalisation dans la consoleDans de tels cas, vous pouvez définir le code d'erreur par défaut. À savoir, nous parlons de l'
500 Internal Server Error
:
app.use((error, req, res, next) => { res.status(error.status || 500) res.json({ status: error.status, message: error.message, stack: error.stack }) })
▍Modification du code d'état d'erreur
Supposons que nous allons lire un certain fichier en utilisant les données fournies par l'utilisateur. Si un tel fichier n'existe pas, cela signifie que nous devons donner une erreur
400 Bad Request
. Après tout, le serveur est introuvable car le fichier est introuvable.
Dans ce cas, vous devez utiliser la construction try / catch pour intercepter l'erreur d'origine. Ensuite, vous devez recréer l'objet d'erreur à l'aide de
createError
:
app.get('/testing', asyncHandler(async (req, res, next) => { try { const { file } = req.body const contents = await readFilePromise(path.join(__dirname, file)) } catch (error) { throw createError(400, `File ${file} does not exist`) } })
▍ Gestion des erreurs 404
Si la demande a traversé tous les gestionnaires et itinéraires intermédiaires, mais n'a pas été traitée, cela signifie que le point de terminaison correspondant à une telle demande n'a pas été trouvé.
Pour gérer les erreurs
404 Not Found
, vous devez ajouter, entre les routes et le gestionnaire d'erreurs, un gestionnaire supplémentaire. Voici à quoi ressemble la création de l'objet d'erreur 404:
Détails de l'erreur▍ ERR_HTTP_HEADERS_SENT notes d'erreur
Ne paniquez pas si vous voyez le message d'erreur
ERR_HTTP_HEADERS_SENT: Cannot set headers after they are sent to the client
. Cela se produit parce que dans le même gestionnaire, la méthode qui définit les en-têtes de réponse est appelée à plusieurs reprises. Voici les méthodes qui appellent pour définir automatiquement les en-têtes de réponse:
- res.send
- res.json
- res.render
- res.sendFile
- res.sendStatus
- res.end
- res.redirect
Ainsi, par exemple, si vous appelez les
res.json
res.render
et
res.json
dans le même gestionnaire de réponses, vous obtiendrez l'erreur
ERR_HTTP_HEADERS_SENT
:
app.get('/testing', (req, res) => { res.render('new-page') res.json({ message: '¯\_(ツ)_/¯' }) })
Par conséquent, si vous rencontrez cette erreur, vérifiez soigneusement le code du gestionnaire de réponses et assurez-vous qu'il n'y a aucune situation dans laquelle plusieurs des méthodes décrites ci-dessus sont appelées.
▍ Gestion des erreurs et streaming de données
Si quelque chose ne va pas lors du streaming de la réponse vers le frontend, vous pouvez rencontrer la même erreur
ERR_HTTP_HEADERS_SENT
.
Dans ce cas, la gestion des erreurs doit être transmise aux gestionnaires standard. Un tel gestionnaire enverra une erreur et fermera automatiquement la connexion.
app.use((error, req, res, next) => {
Résumé
Aujourd'hui, je vous ai dit tout ce que je sais sur la gestion des erreurs dans Express. J'espère que cela vous aidera à écrire des applications Express plus fiables.
Chers lecteurs! Comment gérez-vous les erreurs dans vos projets Node.js?
