Bài trước: Web back-end (14) - Lập trình hướng sự kiện
Sau bài học trước, chúng ta đã có ý niệm về lập trình hướng sự kiện (event-driven), đã thực hành viết một chương trình đơn giản về lập trình hướng sự kiện trong môi trường Nodejs.
Trong phần này, chúng ta sẽ tìm hiểu về lập trình hướng sự kiện, route handler và middleware trong môi trường Express.
15.1 Lập trình hướng sự kiện trong Express
Express là một framework, xây dựng trên nền tảng Nodejs. Express sử dụng mô hình lập trình hướng sự kiện để xử lý các HTTP request, đọc/ghi tập tin, làm việc với cơ sở dữ liệu, websocket, stream.
Chúng ta cùng tìm hiểu cách Express sử dụng mô hình lập trình hướng sự kiện để xử lý các HTTP request.
Trong mô hình này:
- Mỗi request từ client (như GET, POST, PUT, DELETE) được xem là một sự kiện (Event).
- Các module http, fs, stream là các Bộ quản lý sự kiện (Event Emitter) của Express.
- Express sử dụng Vòng lặp sự kiện (Event Loop) của Node.js để lắng nghe và xử lý các sự kiện theo kiểu bất đồng bộ (asynchronous), không chặn luồng (non-blocking).
- Các route handler và middleware đóng vai trò như các Hàm xử lý sự kiện (Event Handler), được gọi khi sự kiện tương ứng xảy ra.
Xem hình minh họa.
15.2 Thực hành với GET request
Để hiểu rõ hơn về lập trình hướng sự kiện trong Express, chúng ta cùng thực hành với GET request.
Tình huống cụ thể như sau:
- Client gửi GET request tới web server
- Web server phát hiện sự kiện GET request và chuyển nó đến Express.
- Express kiểm tra URL và method (GET) để tìm route handler phù hợp.
- Hàm callback (route handler) được gọi để xử lý sự kiện, trả về response cho client.
[index.js]
'use strict'
const express = require('express')
const app = express();
const port = process.env.PORT || 9000
// Express lắng nghe sự kiện GET request, tại route /
// nếu có sự kiện, gọi hàm callback (route handler) tương ứng
app.get('/', (req, res) =>
{
const name = req.query.name;
res.send(`Web server chào bạn ${name}`);
});
// khoi dong web server
app.listen(port, () => {
console.log(`server dang chay tren cong ${port}`);
});
Lưu lại mã nguồn tập tin index.js, khởi động lại web server.
Mở trình duyệt web, nhập đường dẫn sau:
http://localhost:9000/?name=Teo
Giao diện của trình duyệt web sẽ có dòng nội dung sau:
Web server chào bạn Teo
Sử dụng Middleware cho GET request
Chúng ta sẽ sử dụng middleware với vai trò như là một Event Handler (Hàm xử lý sự kiện) cho GET request.
[index.js]
'use strict'
const express = require('express')
const app = express();
const port = process.env.PORT || 9000
// Middleware: ghi log mỗi khi có GET request
app.use((req, res, next) =>
{
console.log(`[${new Date().toISOString()}] nhận GET request tại ${req.url}`)
// Chuyển tiếp sự kiện đến route handler
next();
});
// Express lắng nghe sự kiện GET request, tại route /
// nếu có sự kiện, gọi hàm callback (route handler) tương ứng
app.get('/', (req, res) =>
{
const name = req.query.name;
res.send(`Web server chào bạn ${name}`);
});
// khoi dong web server
app.listen(port, () => {
console.log(`server dang chay tren cong ${port}`);
});
Lưu lại mã nguồn tập tin index.js, khởi động lại web server.
Mở trình duyệt web, nhập đường dẫn sau:
http://localhost:9000/?name=Teo
Giao diện của trình duyệt web sẽ có dòng nội dung sau:
Web server chào bạn Teo
Và cửa sổ console của Web server sẽ có dòng thông báo như sau:
server dang chay tren cong 9000
[2025-03-31T11:54:20.737Z] nhận GET request tại /?name=Teo
15.3 Route handler và Middleware trong Express
Ở phần trước, bạn đã thực hành trải nghiệm với Route handler và Middleware.
Phần này, chúng ta sẽ tìm hiểu kĩ hơn về 2 khái niệm này.
Route handler
Route handler là các hàm xử lý được gắn với một luồng (route) cụ thể trong ứng dụng Express. Chúng được gọi khi một HTTP request (như GET, POST, PUT, DELETE) từ client khớp với route và method tương ứng. Route handler đóng vai trò như Event handler trong lập trình hướng sự kiện, xử lý logic chính cho request và trả về response.
Route handler nhận 3 tham số chính:
- req (request): đối tượng chứa thông tin về request từ client (URL, headers, body).
- res (response): đối tượng dùng để gửi response về client.
- next (optional): hàm gọi để chuyển tiếp request sang middleware hoặc handler tiếp theo (nếu có).
Cú pháp:
app.METHOD(path, callback);
- Trong đó METHOD là HTTP method (get, post, put, delete), path là luồng, và callback là Route handler.
// Express lắng nghe sự kiện GET request, tại route /
// nếu có sự kiện, gọi hàm callback (route handler) tương ứng
app.get('/', (req, res) =>
{
const name = req.query.name;
res.send(`Web server chào bạn ${name}`);
});
Đặc điểm của Route handler:
- Cụ thể cho route và method: mỗi Route handler chỉ được gọi khi request khớp (match) với route và HTTP method đã định nghĩa.
- Xử lý logic chính: thường chứa logic nghiệp vụ như truy vấn cơ sở dữ liệu, xử lý dữ liệu, hoặc trả về kết quả.
- Có thể nối tiếp: nhiều Route handler có thể được gắn vào cùng một route bằng cách truyền nhiều callback hoặc dùng next().
Ví dụ nối tiếp Route handler
[index.js]
'use strict'
const express = require('express')
const app = express();
const port = process.env.PORT || 9000
// Nối tiếp Route handler
app.get('/profile', (req, res, next) =>
{
console.log('Kiểm tra quyền truy cập...');
req.user = { name: "Ti"}; // Giả lập thêm dữ liệu
next(); // Chuyển tiếp
},
(req, res) => {
res.send(`Chào bạn: ${req.user.name}`);
}
);
// khoi dong web server
app.listen(port, () => {
console.log(`server dang chay tren cong ${port}`);
});
Lưu lại mã nguồn tập tin index.js, khởi động lại web server.
Mở trình duyệt web, nhập đường dẫn sau:
http://localhost:9000/profile
Giao diện của trình duyệt web sẽ có dòng nội dung sau:
Chào bạn: Ti
Middleware
Middleware là các hàm được thực thi trong quá trình xử lý một HTTP request, trước hoặc sau Route handler. Chúng có thể:
- Xử lý request (như xác thực, ghi log).
- Sửa đổi đối tượng req hoặc res.
- Chuyển tiếp request bằng next() hoặc dừng luồng xử lý bằng cách gửi response.
Middleware hoạt động như một "lớp trung gian" trong pipeline (dây chuyền, đường ống) xử lý request, giúp tách biệt logic chung khỏi Route handler.
Cấu trúc cơ bản
- Middleware cũng nhận 3 tham số: req, res, và next.
- Được đăng ký bằng app.use() (áp dụng cho tất cả route) hoặc gắn vào route cụ thể.
Cú pháp:
app.use(middlewareFunction);
Ví dụ:
// Middleware: ghi log mỗi khi có GET request
app.use((req, res, next) =>
{
console.log(`[${new Date().toISOString()}] nhận GET request tại ${req.url}`)
// Chuyển tiếp sự kiện đến route handler
next();
});
Xem hình minh họa.
Các loại
Middleware
[1] Application-level middleware: áp dụng cho toàn bộ ứng dụng với app.use().
// middleware mức ứng dụng
app.use((req, res, next) =>
{
req.timestamp = new Date();
next();
});
app.get('/',(req, res) => {
res.send(`Khach truy cap web ap luc ${req.timestamp.toISOString()}`);
});
[2] Router-level middleware: áp dụng cho một nhóm route cụ thể bằng express.Router()
[3] Error-handling middleware: xử lý lỗi, nhận thêm tham số err.
[4] Built-in middleware: các middleware do Express cung cấp sẵn như express.json(), express.static().
[5] Third-party middleware: middleware của các nhà cung cấp khác, ví dụ body-parser, cors, morgan.
15.4 Bài tập
Bài tập 15.1 Cài đặt các đoạn mã trong bài học.
Câu hỏi 15.2 Mô hình lập trình hướng sự kiện của Express. Phát biểu nào sau đây không đúng?
A. Mỗi request từ client (như GET, POST, PUT, DELETE) được xem là một sự kiện (Event).
B. Các module http, fs, stream là các Bộ quản lý sự kiện (Event Emitter) của Express.
C. Express sử dụng Vòng lặp sự kiện (Event Loop) của trình duyệt để lắng nghe và xử lý các sự kiện theo kiểu bất đồng bộ (asynchronous), không chặn luồng (non-blocking).
D. Các route handler và middleware đóng vai trò như các Hàm xử lý sự kiện (Event Handler), được gọi khi sự kiện tương ứng xảy ra.
Câu hỏi 15.3 Route handler trong Express là gì? Phát biểu nào sau đây không đúng?
A. Route handler chỉ được gọi khi request khớp với route và HTTP method đã định nghĩa.
B. Route handler thường chứa logic nghiệp vụ như truy vấn cơ sở dữ liệu hoặc xử lý dữ liệu.
C. Route handler có thể chuyển tiếp request sang middleware hoặc handler tiếp theo bằng hàm next().
D. Chỉ có duy nhất một Route handler được gắn vào một route.
15.4. Middleware trong Express là gì? Phát biểu nào sau đây không đúng?
A. Middleware là các hàm được thực thi trong quá trình xử lý một HTTP request, trước hoặc sau Route handler.
B. Xử lý request (như xác thực, ghi log).
C. Sửa đổi đối tượng req hoặc res.
D. Middleware nhận 2 tham số: req, res.