Menu
CoddyTech

Die Reihenfolge ist wichtig

Teil des Abschnitts Express-Grundlagen der Node.js-Journey von Coddy. Lektion 14 von 23.

Express führt Middleware und Routen in der Reihenfolge aus, in der dein Code sie hinzufügt, und eine Route, die eine Antwort sendet, beendet die Anfrage an dieser Stelle.

app.get('/bikes', (req, res) => {
    res.json(bikes);
});

app.use((req, res, next) => {
    res.set('Cache-Control', 'no-store');
    next();
});

res.set(name, value) fügt der Antwort einen Header hinzu und muss ausgeführt werden, bevor die Antwort gesendet wird. Hier antwortet GET /bikes, bevor die Middleware erreicht wird, daher erhält die Antwort nie den Header: Die Middleware sieht nur Anfragen, die von keiner darüberliegenden Route beantwortet wurden. Middleware, die jede Antwort beeinflussen soll, kommt vor die Routen und vor express.static.

challenge icon

Aufgabe

Einfach

Jede Antwort erhält eine ID, damit du die Anfrage in deinem Protokoll finden kannst, wenn ein Besucher ein Problem meldet. Jede Antwort braucht eine: Seiten, API-Daten und Dateien aus public.

  1. Importiere in server.js randomUUID aus node:crypto. Jeder Aufruf gibt eine neue zufällige ID zurück, zum Beispiel 3b241101-e2bb-4255-8caf-4136c566a962.
  2. Füge eine Middleware hinzu, die einen Antwort-Header namens X-Request-Id mit einer neuen randomUUID() für jede Anfrage setzt und anschließend next() aufruft.
  3. Platziere sie so, dass jede Anfrage sie durchläuft, auch die für Dateien, die express.static sendet. Eine Antwort erhält den Header nur, wenn die Middleware ausgeführt wird, bevor etwas antwortet.

Probiere es aus: Drücke auf „Run“ und sende zweimal /api/recipes. Im Tab „Headers“ hat X-Request-Id jedes Mal einen anderen Wert. Sende /style.css und /: Beide enthalten ebenfalls ein X-Request-Id.

Probier es selbst

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') sendet reinen Text, sodass jeder Titel in einer eigenen Zeile erscheint.
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');
});

Alle Lektionen in Express-Grundlagen

Übe selbstständig: Express-Playground