Express là framework web tối giản phổ biến nhất của Node.js. Bài này học Express 5: định tuyến, tham số, middleware, phục vụ tệp tĩnh, xử lý form, render giao diện bằng EJS và xử lý lỗi tập trung.
- Tạo ứng dụng Express, định tuyến theo phương thức
- Đọc req.params, req.query, req.body
- Viết và dùng middleware, Router
- Render EJS, phục vụ tĩnh, xử lý 404 và lỗi
- Middleware
- Hàm (req, res, next) chạy giữa yêu cầu và phản hồi.
- Router
- Nhóm các tuyến có chung tiền tố.
- Template engine
- Sinh HTML từ mẫu + dữ liệu (EJS, Pug, Handlebars).
Một số khái niệm
Một yêu cầu đi qua chuỗi middleware theo thứ tự khai báo: ghi log → đọc body → kiểm tra đăng nhập → tuyến xử lý. Mỗi middleware hoặc trả phản hồi, hoặc gọi next() để chuyển tiếp. Express 5 hỗ trợ hàm async: lỗi ném ra trong hàm async tự được chuyển tới middleware xử lý lỗi.
Ứng dụng Express
npm install express ejs// src/app.js
import express from 'express';
const app = express();
app.set('view engine', 'ejs');
app.set('views', 'src/views');
app.use(express.static('public')); // tệp tĩnh: /css/style.css
app.use(express.urlencoded({ extended: true })); // body từ form
app.use(express.json()); // body JSON
app.use((req, res, next) => { // middleware ghi log
const bd = Date.now();
res.on('finish', () => console.log(req.method, req.originalUrl, res.statusCode, Date.now() - bd + 'ms'));
next();
});
const ds = [{ id: 1, ten: 'Lò Văn An', lop: 'K66 Tin' }];
app.get('/', (req, res) => res.render('index', { tieuDe: 'Trang chủ', ds }));
app.get('/sinhvien/:id', (req, res) => {
const sv = ds.find(s => s.id === Number(req.params.id));
if (!sv) return res.status(404).render('404');
res.render('chi-tiet', { sv });
});
app.post('/sinhvien', (req, res) => {
const ten = (req.body.ten ?? '').trim();
if (ten.length < 3) return res.status(422).render('index', { tieuDe: 'Trang chủ', ds, loi: 'Tên quá ngắn' });
ds.push({ id: ds.length + 1, ten, lop: req.body.lop });
res.redirect(303, '/'); // PRG
});
app.use((req, res) => res.status(404).render('404')); // 404
app.use((err, req, res, next) => { // lỗi tập trung
console.error(err);
res.status(500).send('Đã có lỗi xảy ra');
});
app.listen(process.env.PORT ?? 3000);Giao diện EJS
<!-- src/views/index.ejs -->
<!doctype html><html lang="vi"><head><meta charset="utf-8"><title><%= tieuDe %></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/css/bootstrap.min.css"></head>
<body class="container py-4">
<h1><%= tieuDe %></h1>
<% if (locals.loi) { %><div class="alert alert-danger"><%= loi %></div><% } %>
<ul class="list-group mb-3">
<% ds.forEach(sv => { %>
<li class="list-group-item"><a href="/sinhvien/<%= sv.id %>"><%= sv.ten %></a> – <%= sv.lop %></li>
<% }) %>
</ul>
<form method="post" action="/sinhvien" class="d-flex gap-2"><input name="ten" class="form-control" placeholder="Họ tên"><input name="lop" class="form-control" placeholder="Lớp"><button class="btn btn-success">Thêm</button></form>
</body></html><%= %> in giá trị đã mã hóa HTML (chống XSS); <% %> chạy mã JS. Giao diện dùng Bootstrap 5 (loạt Bootstrap 5).
Router tách tuyến
// src/routes/sinhvien.js
import { Router } from 'express';
const r = Router();
r.get('/', (req, res) => res.json(ds));
r.get('/:id', (req, res) => res.json(ds.find(s => s.id == req.params.id) ?? null));
export default r;
// app.js
import sinhVienRouter from './routes/sinhvien.js';
app.use('/api/sinhvien', sinhVienRouter);Cấu trúc thư mục gợi ý: src/routes, src/controllers, src/models, src/views, src/middlewares: chính là mô hình MVC (xem loạt PHP Bài 17).
Thứ tự app.use quan trọng: middleware 404 phải đặt sau mọi tuyến; middleware lỗi (4 tham số) đặt cuối cùng.
- Tạo ứng dụng Express hiển thị danh sách sinh viên bằng EJS.
- Thêm trang chi tiết /sinhvien/:id và trang 404.
- Viết middleware chặn truy cập /admin nếu thiếu query ?key=.
- Tách tuyến API vào Router riêng.
- app.get/post/put/delete(đường-dẫn, xử-lý).
- req.params, req.query, req.body; res.json, res.render, res.redirect.
- Middleware (req, res, next), Router, static.
- Xử lý 404 và lỗi tập trung ở cuối.