Menu
CoddyTech

הסדר חשוב

חלק מהיחידה יסודות Express במסלול ה-Node.js של Coddy. שיעור 14 מתוך 23.

Express מפעיל תוכנות ביניים ונתיבים לפי הסדר שבו הקוד שלך מוסיף אותם, ונתיב שמחזיר תשובה מסיים שם את הבקשה.

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

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

res.set(name, value) מוסיפה כותרת לתגובה, ויש להפעיל אותה לפני שליחת התגובה. כאן GET /bikes מחזיר תשובה לפני שמגיעים לתוכנת הביניים, ולכן התגובה שלו לעולם לא מקבלת את הכותרת: תוכנת הביניים רואה רק בקשות שאף נתיב שמופיע לפניה לא ענה עליהן. תוכנת ביניים שאמורה להשפיע על כל התגובות צריכה להופיע לפני הנתיבים ולפני express.static.

challenge icon

אתגר

קל

כל תגובה מקבלת מזהה, כך שכאשר מבקר מדווח על בעיה, אפשר למצוא את הבקשה שלו ביומן. כל תגובה זקוקה למזהה: דפים, נתוני API וקבצים מתוך public.

  1. ב־server.js, יש לייבא את randomUUID מתוך node:crypto. כל קריאה מחזירה מזהה אקראי חדש, כמו 3b241101-e2bb-4255-8caf-4136c566a962.
  2. יש להוסיף תווכה שמגדירה כותרת תגובה בשם X-Request-Id, המכילה randomUUID() חדש עבור כל בקשה, ואז קוראת ל־next().
  3. יש למקם אותה כך שכל בקשה תעבור דרכה, כולל הקבצים ש־express.static שולחת. תגובה מקבלת את הכותרת רק אם התווכה פועלת לפני שמשהו משיב.

נסו זאת: לחצו על הפעלה ושלחו את /api/recipes פעמיים. בכרטיסייה Headers, הערך של X-Request-Id שונה בכל פעם. שלחו את /style.css ואת /: גם כל אחת מהן נושאת X-Request-Id.

נסו בעצמכם

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') שולחת טקסט פשוט, כך שכל כותרת מופיעה בשורה משלה.
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');
});

כל השיעורים ביחידה יסודות Express

תרגלו בעצמכם: Express אונליין