Express : fichiers statiques, envois et vues
Fichiers statiques
Section intitulée « Fichiers statiques »import express from 'express';import path from 'node:path';import { fileURLToPath } from 'node:url';
const dossier = path.dirname(fileURLToPath(import.meta.url));const app = express();
app.use( express.static(path.join(dossier, '..', 'public'), { maxAge: '1d', index: 'index.html', dotfiles: 'ignore', }),);public/style.css est alors disponible à /style.css. Préfixer l’URL :
app.use('/assets', express.static(path.join(dossier, '..', 'public')));Utiliser des chemins absolus (construits avec import.meta.url) : un chemin relatif dépend du dossier courant au lancement.
En production, laisser le reverse proxy (Caddy, Nginx) servir les fichiers statiques : plus rapide et sans passer par Node.js (voir Sécurité et production).
Envoyer et télécharger un fichier
Section intitulée « Envoyer et télécharger un fichier »app.get('/rapport.pdf', (req, res) => { res.sendFile(path.join(dossier, '..', 'fichiers', 'rapport.pdf'));});
app.get('/telecharger', (req, res) => { res.download( path.join(dossier, '..', 'fichiers', 'rapport.pdf'), 'rapport-2026.pdf', );});Recevoir des fichiers avec multer
Section intitulée « Recevoir des fichiers avec multer »npm install multerimport multer from 'multer';import crypto from 'node:crypto';import path from 'node:path';
const televersement = multer({ storage: multer.diskStorage({ destination: '/srv/monapi/uploads', filename: (req, fichier, cb) => cb( null, crypto.randomUUID() + path.extname(fichier.originalname).toLowerCase(), ), }), limits: { fileSize: 5 * 1024 * 1024, files: 1 }, fileFilter: (req, fichier, cb) => { const autorises = ['image/png', 'image/jpeg', 'application/pdf']; cb(null, autorises.includes(fichier.mimetype)); },});
app.post('/api/fichiers', televersement.single('fichier'), (req, res) => { if (!req.file) return res.status(400).json({ erreur: 'fichier refusé' }); res.status(201).json({ nom: req.file.filename, taille: req.file.size });});curl -F 'fichier=@photo.jpg' http://127.0.0.1:3000/api/fichiersRègles de sécurité pour les téléversements :
- Générer le nom de stockage côté serveur (jamais le nom envoyé par le client).
- Limiter la taille et le nombre de fichiers.
- Contrôler le type (le
mimetypeenvoyé par le client est falsifiable : pour des cas sensibles, contrôler le contenu). - Stocker hors du dossier servi en statique, ou dans un dossier où rien ne s’exécute.
- Aligner la limite du reverse proxy (
client_max_body_sizepour Nginx).
Moteur de vues
Section intitulée « Moteur de vues »Express sait produire des pages HTML à partir de modèles. Exemple avec EJS :
npm install ejsapp.set('view engine', 'ejs');app.set('views', path.join(dossier, '..', 'views'));
app.get('/clients', (req, res) => { res.render('clients', { titre: 'Clients', clients: [{ nom: 'Alice' }, { nom: 'Bob' }], });});views/clients.ejs :
<!doctype html><html lang="fr"><head><meta charset="utf-8"><title><%= titre %></title></head><body> <h1><%= titre %></h1> <ul> <% clients.forEach((c) => { %> <li><%= c.nom %></li> <% }) %> </ul></body></html><%= … %> échappe le HTML (protection contre le XSS) ; <%- … %> insère sans échapper : à réserver à du HTML de confiance.
Cookies et sessions
Section intitulée « Cookies et sessions »npm install express-sessionimport session from 'express-session';
app.set('trust proxy', 1);app.use( session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false, cookie: { httpOnly: true, secure: true, sameSite: 'lax', maxAge: 1000 * 60 * 60 * 8, }, }),);
app.post('/connexion', (req, res) => { req.session.utilisateur = { id: 1 }; res.sendStatus(204);});| Réglage | Raison |
|---|---|
httpOnly |
Cookie inaccessible au JavaScript |
secure |
Envoyé en HTTPS seulement |
sameSite: 'lax' |
Limite les requêtes intersites (CSRF) |
secret |
Variable d’environnement longue et aléatoire (openssl rand -base64 48) |
Le stockage de sessions par défaut est en mémoire : il est perdu à chaque redémarrage et inadapté au mode cluster ou à la production. Utiliser un stockage externe (par exemple Redis, voir Redis : installation).
Dépannage
Section intitulée « Dépannage »| Symptôme | Piste |
|---|---|
404 sur un fichier statique |
Chemin du dossier (utiliser un chemin absolu), nom de fichier, ordre des app.use |
Error: Failed to lookup view |
views mal défini ou fichier absent |
multer : LIMIT_FILE_SIZE |
Fichier trop gros : limite fileSize |
413 Request Entity Too Large |
Limite du reverse proxy ou express.json({ limit }) |
| Session perdue à chaque requête | cookie.secure: true sans HTTPS ni trust proxy derrière le proxy |
EACCES à l’écriture d’un envoi |
Droits du dossier de destination pour l’utilisateur du service |
Ubuntu 24.04 et 26.04 : différences à connaître
Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »Aucune. Veiller aux droits du dossier d’envois pour l’utilisateur qui exécute le service (voir systemd : écrire un service).