Menu
CoddyTech

Penangan 404

Termasuk bagian Dasar-Dasar Express dalam perjalanan Node.js di Coddy. Pelajaran 16 dari 23.

Express menampilkan halamannya sendiri untuk path yang tidak dikenal, Cannot GET /x, yang tidak cocok dengan situs maupun API-mu.

app.use((req, res) => {
    res.status(404).send('No forecast here. Try /weather/oslo');
});

Middleware tanpa path berjalan untuk setiap permintaan yang sampai ke sana. Letakkan middleware ini setelah semua route dan setelah express.static: permintaan yang dijawab oleh keduanya tidak akan sampai ke sana, jadi middleware ini hanya melihat permintaan yang tidak dijawab oleh apa pun. Middleware ini memberikan jawaban, jadi tidak memerlukan next.

req.path adalah path tanpa query string, jadi req.path.startsWith('/api/') membedakan panggilan API dari halaman.

challenge icon

Tantangan

Mudah

Path yang tidak ada menampilkan halaman Cannot GET sederhana dari Express. Ganti dengan halaman buatanmu sendiri: JSON untuk API, dan halaman yang ramah bagi pengunjung.

  1. Di server.js, setelah semua route dan setelah express.static, tambahkan satu app.use terakhir tanpa path. Permintaan yang sudah ditangani tidak akan sampai ke sana, jadi middleware ini hanya menerima permintaan yang belum ditangani.
  2. Jika path diawali dengan /api/, middleware ini merespons dengan status 404 dan JSON berikut: {"error": "Not found"}
  3. Untuk path lainnya, middleware ini merespons dengan status 404 dan halaman HTML yang berisi kata-kata Page not found, misalnya <h1>Page not found</h1>. Menambahkan tautan kembali ke halaman beranda juga merupakan sentuhan yang bagus.

Coba: Tekan tombol “Jalankan” dan kirim /api/nope. Kamu seharusnya melihat status 404 dan {"error":"Not found"}. Kirim /nope: status 404, ditampilkan sebagai halaman yang bertuliskan Page not found. Kirim /api/recipes/1: status 200 dan Tomato Soup, yang menunjukkan bahwa route-mu tetap diproses lebih dahulu.

Coba sendiri

import { escapeHtml } from './html.js';
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'));

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') mengirim teks biasa, sehingga setiap judul tampil di baris tersendiri.
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');
});

Semua pelajaran di Dasar-Dasar Express

Latihan sendiri: Playground Express