Menu
CoddyTech

첫 번째 미들웨어

Coddy Node.js 여정의 Express 기초 섹션에 포함된 레슨. 23개 중 13번째.

로그에 한 줄을 쓰는 것처럼 모든 요청에 공통으로 필요한 작업이 있는데, 이를 각 경로에 복사해 넣는 일은 끝이 없습니다. 모든 요청에는 req.method에 메서드가 있습니다. GET은 무언가를 가져오고, POST는 무언가를 보냅니다.

let visits = 0;

app.use((req, res, next) => {
    visits++;
    next();
});

app.use에 전달하는 함수는 미들웨어입니다. Express는 미들웨어가 추가된 순서대로, 그 아래에 있는 경로보다 먼저 모든 요청에 대해 미들웨어를 실행합니다. 이 함수는 세 번째 인수인 next를 받습니다. next()를 호출하면 요청이 다음 단계로 넘어갑니다. 응답도 하지 않고 next()도 호출하지 않는 미들웨어가 있으면 요청은 영원히 대기 상태에 머뭅니다.

지난 장에서 살펴본 express.static도 미들웨어입니다. 파일을 찾으면 응답하고, 찾지 못하면 next()를 호출합니다.

challenge icon

챌린지

쉬움

서버가 받는 모든 요청을 한 줄씩 기록하면 방문자가 무엇을 요청하는지 확인할 수 있습니다.

  1. server.js에서 const app = express(); 바로 다음에 app.use를 사용해 미들웨어를 추가하세요. 이 위치에 두면 모든 경로보다 먼저 실행됩니다.
  2. 각 요청에 대해 Console에 한 줄을 출력합니다. 요청의 메서드, 공백, 그리고 경로를 출력합니다. /recipes/2 요청은 GET /recipes/2를 출력합니다. 메서드는 req.method에 있고(GET, POST 등), 경로는 req.url에 있습니다.
  3. 출력한 다음 next()를 호출하여 요청이 경로로 계속 진행되게 합니다.

직접 해보기: ‘플레이’를 눌러 실행한 다음 /recipes/2를 요청하세요. Pancakes가 표시되고 Console에는 GET /recipes/2가 표시됩니다. /api/recipes를 요청하면 평소처럼 목록이 표시되고 Console에는 GET /api/recipes가 표시됩니다. /nope를 요청하면 404가 표시되며 Console에는 계속 GET /nope가 표시됩니다. 미들웨어가 Express가 경로를 찾기 전에 실행되기 때문입니다.

직접 해보기

import { escapeHtml } from './html.js';
import express from 'express';
import { recipes } from './data.js';

const app = express();

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');
});
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Express 기초의 모든 레슨

직접 연습해 보세요: Express 플레이그라운드