Der 404-Handler
Teil des Abschnitts Express-Grundlagen der Node.js-Journey von Coddy. Lektion 14 von 20.
Express beantwortet einen unbekannten Pfad mit einer eigenen Seite, Cannot GET /x, die weder zu deiner Website noch zu deiner API passt.
app.use((req, res) => {
res.status(404).send('No forecast here. Try /weather/oslo');
});Eine Middleware ohne Pfad wird bei jeder Anfrage ausgeführt, die sie erreicht. Setze sie nach jeder Route und nach express.static: Anfragen, die dort beantwortet wurden, gelangen nie hierher, sodass sie nur die Anfragen sieht, auf die nichts geantwortet hat. Sie beantwortet die Anfrage, daher braucht sie kein next.
req.path ist der Pfad ohne die Abfragezeichenfolge, daher unterscheidet req.path.startsWith('/api/') einen API-Aufruf von einer Seite.
Aufgabe
Einfach- Ein Pfad unter
/api/, auf den nichts antwortet, liefert404mit{ "error": "Not found" }. - Jeder andere Pfad liefert eine HTML-Seite mit dem Statuscode
404und der MeldungPage not found.
Sende GET /api/nope, öffne /nope in der Seitenansicht und sende dann GET /api/recipes/1.
Probier es selbst
import express from 'express';
import { randomUUID } from 'node:crypto';
import { recipes } from './data.js';
const app = express();
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
app.use((req, res, next) => {
res.set('X-Request-Id', randomUUID());
next();
});
app.use(express.json());
app.use(express.static('public'));
const escapeHtml = (text) =>
text
.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll('"', '"');
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 einfachen 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.post('/api/recipes', (req, res) => {
const { title, tags } = req.body;
if (!title) {
res.status(400).json({ error: 'A recipe needs a title' });
return;
}
const recipe = { id: recipes.length + 1, title, tags: tags ?? [] };
recipes.push(recipe);
res.status(201).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
3Middleware
Dein erstes Middleware