L’ordre compte
Fait partie de la section Les bases d’Express du Journey Node.js de Coddy. Leçon 14 sur 23.
Express exécute les intergiciels et les routes dans l’ordre où votre code les ajoute, et une route qui répond met fin à la requête à cet endroit.
app.get('/bikes', (req, res) => {
res.json(bikes);
});
app.use((req, res, next) => {
res.set('Cache-Control', 'no-store');
next();
});res.set(name, value) ajoute un en-tête à la réponse et doit être exécuté avant l’envoi de celle-ci. Ici, GET /bikes répond avant que l’intergiciel ne soit atteint ; sa réponse ne reçoit donc jamais l’en-tête : l’intergiciel ne voit que les requêtes auxquelles aucune route située au-dessus de lui n’a répondu. Les intergiciels qui doivent agir sur chaque réponse se placent au-dessus des routes et de express.static.
Défi
FacileChaque réponse reçoit un identifiant, afin que vous puissiez retrouver la requête d’un visiteur dans votre journal lorsqu’il signale un problème. Toutes les réponses en ont besoin : les pages, les données de l’API et les fichiers de public.
- Dans
server.js, importezrandomUUIDdepuisnode:crypto. Chaque appel renvoie un nouvel identifiant aléatoire, comme3b241101-e2bb-4255-8caf-4136c566a962. - Ajoutez un middleware qui définit un en-tête de réponse nommé
X-Request-Id, contenant un nouveaurandomUUID()pour chaque requête, puis appellenext(). - Placez-le de manière à ce que chaque requête le traverse, y compris les fichiers envoyés par
express.static. Une réponse ne reçoit l’en-tête que si le middleware s’exécute avant qu’un élément ne réponde.
Essayez : appuyez sur « Jouer » et envoyez /api/recipes deux fois. Dans l’onglet Headers, X-Request-Id a une valeur différente à chaque fois. Envoyez /style.css et / : les deux comportent également un X-Request-Id.
Essayez vous-même
import { escapeHtml } from './html.js';
import express from 'express';
import { recipes } from './data.js';
const app = express();
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.use(express.static('public'));
app.get('/', (req, res) => {
const items = recipes.map((r) => `<li><a href="/recipes/${r.id}">${escapeHtml(r.title)}</a></li>`);
res.send(`<link rel="stylesheet" href="/style.css"><h1>Recipe Box</h1><ul>${items.join('')}</ul>`);
});
// type('text') envoie du texte brut, de sorte que chaque titre s’affiche sur sa propre ligne.
app.get('/recipes', (req, res) => {
const { tag } = req.query;
const list = tag ? recipes.filter((recipe) => recipe.tags.includes(tag)) : recipes;
res.type('text').send(list.map((recipe) => recipe.title).join('\n'));
});
app.get('/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).send('No such recipe');
return;
}
res.send(recipe.title);
});
app.get('/api/recipes', (req, res) => {
res.json(recipes);
});
app.get('/api/recipes/:id', (req, res) => {
const recipe = recipes.find((r) => r.id === Number(req.params.id));
if (!recipe) {
res.status(404).json({ error: 'No such recipe' });
return;
}
res.json(recipe);
});
app.get('/about', (req, res) => {
res.send('Recipe Box collects family recipes.');
});
app.get('/menu', (req, res) => {
res.redirect(301, '/recipes');
});
app.get('/menu/:id', (req, res) => {
res.redirect(301, `/recipes/${req.params.id}`);
});
app.listen(3000, () => {
console.log('Recipe Box is running on port 3000');
});
Toutes les leçons de Les bases d’Express
Entraînez-vous par vous-même : Playground Express