الترتيب مهم
جزء من قسم أساسيات Express في رحلة Node.js على Coddy. الدرس 12 من 20.
يشغّل 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.
التحدي
سهليتضمن كل رد، بما في ذلك الصفحات والملفات، ترويسة X-Request-Id تحتوي على قيمة جديدة من randomUUID() من node:crypto.
أرسل GET /api/recipes مرتين وقارن الترويسات، ثم أرسل GET /style.css.
جرّب بنفسك
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'));
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') نصًا عاديًا، لذا يظهر كل عنوان في سطر مستقل.
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');
});