Express : dépannage
Premiers réflexes
Section intitulée « Premiers réflexes »node --versionnpm ls express # version d'Express installéenode src/serveur.js # lancer à la main : l'erreur s'affichesudo journalctl -u monapi -n 50 --no-pager # service systemdcurl -i http://127.0.0.1:3000/santesudo ss -tlnp | grep 3000Erreurs au démarrage
Section intitulée « Erreurs au démarrage »| Message | Cause et solution |
|---|---|
Cannot find module 'express' |
npm install non exécuté, ou mauvais dossier |
Cannot use import statement outside a module |
"type": "module" absent de package.json |
ERR_MODULE_NOT_FOUND |
En modules ES, extension manquante dans l’import relatif (./routes/clients.js) |
EADDRINUSE |
Port déjà utilisé : sudo ss -tlnp | grep 3000 |
EACCES: permission denied sur le port |
Port inférieur à 1024 sans droit : utiliser un port élevé et un reverse proxy |
TypeError: Missing parameter name at … |
Chemin Express 4 (*, /:id?) : voir la migration vers Express 5 |
SyntaxError à l’import d’un module |
Version de Node.js trop ancienne pour la syntaxe : node --version |
Problèmes de requêtes
Section intitulée « Problèmes de requêtes »| Symptôme | Cause et solution |
|---|---|
Cannot GET /chemin |
Route absente ou méthode différente (POST au lieu de GET) |
req.body vaut undefined |
express.json() manquant, déclaré après la route, ou Content-Type absent |
400 avec entity.parse.failed |
Corps JSON invalide |
413 |
Corps trop gros : limit, ou limite du reverse proxy |
req.query contient un tableau |
Paramètre répété : valider le type |
| Route générique qui masque une autre | Ordre de déclaration |
Cannot set headers after they are sent to the client |
Plusieurs réponses : utiliser return res..., vérifier qu’aucun next() n’est appelé après une réponse |
| La requête ne se termine jamais | Middleware sans next() ni réponse |
404 pour un fichier statique |
Chemin du dossier public (chemin absolu), ordre des middlewares |
L’erreur « blocked by CORS policy » apparaît dans la console du navigateur, pas côté serveur :
import cors from 'cors';app.use( cors({ origin: ['https://exemple.com'], methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'], allowedHeaders: ['Content-Type', 'Authorization'], }),);Vérifier la requête préliminaire :
curl -i -X OPTIONS http://127.0.0.1:3000/api/clients \ -H 'Origin: https://exemple.com' -H 'Access-Control-Request-Method: POST'La réponse doit contenir Access-Control-Allow-Origin.
Erreurs asynchrones
Section intitulée « Erreurs asynchrones »Avec Express 5, une erreur dans un gestionnaire async est transmise au gestionnaire d’erreurs. Elle ne l’est pas si elle survient dans un rappel (callback) ou un setTimeout :
app.get('/x', (req, res) => { setTimeout(() => { throw new Error('perdue'); }, 10); // plante le processus res.send('ok');});Capturer les erreurs dans ces cas ou utiliser des promesses (await). Filets de sécurité :
process.on('unhandledRejection', (raison) => { console.error('rejet non géré', raison);});process.on('uncaughtException', (err) => { console.error('exception', err); process.exit(1);});Après une uncaughtException, quitter le processus : le superviseur (systemd, PM2) le relance dans un état sain.
Mémoire et lenteurs
Section intitulée « Mémoire et lenteurs »node --inspect src/serveur.js # profilage avec les outils de développement du navigateurnode --prof src/serveur.js # profil de performanceps -o pid,rss,cmd -C node # mémoire du processus| Symptôme | Piste |
|---|---|
| Mémoire qui croît | Cache ou tableau global qui grossit, sessions en mémoire, fuite d’écouteurs d’événements |
| Réponses lentes | Requêtes SQL sans index (MariaDB : index et performances), boucle bloquante, readFileSync dans une route |
| Un cœur saturé, les autres libres | Node.js est mono-thread : mode cluster (PM2) |
JavaScript heap out of memory |
Fuite, ou traitement de grosses données en mémoire : flux (streams), pagination |
Éviter dans les gestionnaires les fonctions synchrones qui bloquent (fs.readFileSync, crypto.pbkdf2Sync, boucles longues) : elles figent toutes les requêtes.
Derrière un reverse proxy
Section intitulée « Derrière un reverse proxy »| Symptôme | Piste |
|---|---|
req.ip vaut 127.0.0.1 |
app.set('trust proxy', 1) |
req.protocol vaut http |
trust proxy et X-Forwarded-Proto |
Redirection vers http:// |
Idem |
Cookie secure non enregistré |
trust proxy, HTTPS effectif |
| Limitation de débit commune à tous | trust proxy |
Migrer d’Express 4 à Express 5
Section intitulée « Migrer d’Express 4 à Express 5 »npm install express@5npm ls expressRechercher dans le code les points suivants :
grep -rnE "app\.del\(|req\.param\(|res\.redirect\('back'|\.send\([0-9]{3}\)" src/grep -rnE "['\"]/[^'\"]*\*[^'\"]*['\"]|\?['\"]" src/ | head| À corriger | Remplacement |
|---|---|
app.del() |
app.delete() |
req.param('x') |
req.params.x, req.body.x ou req.query.x |
res.send(404) |
res.sendStatus(404) ou res.status(404).send(...) |
Chemin * |
/*splat |
Chemin /:id? |
{/:id} |
| Expression régulière dans un chemin | Valider dans le gestionnaire |
req.body supposé {} |
req.body ?? {} |
Un try/catch + next(err) existant continue de fonctionner.
node --test # lanceur intégrénode --test --watchUn test qui ne se termine pas : serveur non fermé (serveur.close()), connexion à la base ouverte (pool.end()).
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Les diagnostics sont identiques sur les deux versions. Vérifier que la version de Node.js installée satisfait Express 5 (18 ou plus) ; les mises à jour d’Ubuntu n’affectent pas un Node.js installé avec nvm.