# Express.js là gì? Web framework tối giản cho Node.js

> Express.js là framework tối giản cho Node.js, dùng định tuyến và middleware để dựng ứng dụng web và API. Kèm những thay đổi lớn của Express 5 so với bản 4.

Nguồn: https://camnangai.com/ky-thuat/expressjs-la-gi  
Xuất bản: 2026-08-19

**Express.js** là một web framework tối giản, linh hoạt và không áp đặt (unopinionated) chạy trên
  [Node.js](https://camnangai.com/ky-thuat/nodejs-la-gi). Nó phủ một lớp mỏng lên môi trường chạy (runtime), đủ để bạn
  dựng ứng dụng web và API mà không che lấp các tính năng cốt lõi của Node.js.


Thay vì áp một bộ quy tắc cứng nhắc, Express chỉ lo phần thiết yếu: xử lý [HTTP](https://camnangai.com/ky-thuat/http-la-gi)
request và middleware. Phần còn lại là việc của bạn: tổ chức thư mục ra sao, lắp thêm thư viện
nào từ [npm](https://camnangai.com/ky-thuat/npm-la-gi).

![Express.js là lớp framework mỏng, tối giản phủ trên môi trường chạy Node.js](https://camnangai.com/articles/expressjs-la-gi/01-infographic-vn.webp)

## Express.js là gì?

**Express.js** là một lớp mỏng nằm trên Node.js. Nó không tái định nghĩa cách Node.js hoạt động. Nó
chỉ dọn giúp bạn mấy việc lặp đi lặp lại: định tuyến, đọc dữ liệu gửi lên, dựng phản hồi trả về.
Framework này đứng trên bốn trụ cột: ứng dụng web (đơn trang hoặc đa trang), API
(các dịch vụ RESTful), hiệu năng (giữ nguyên tốc độ của Node.js) và hệ thống middleware.

![Bốn trụ cột của Express.js đặt trên môi trường chạy Node.js: ứng dụng web, API, hiệu năng và middleware](https://camnangai.com/articles/expressjs-la-gi/02-vn.webp)

Nhưng cái quyết định trải nghiệm dùng Express hằng ngày lại nằm ở chữ "unopinionated", tức không áp
đặt. Express không bắt bạn dùng một cấu trúc thư mục cụ thể, cũng không chọn sẵn ORM hay template
engine nào. Đó là con dao hai lưỡi. Một mặt, bạn tối ưu hệ thống theo đúng nhu cầu của mình. Mặt
khác, nếu cả đội không thống nhất trước các quy ước rõ ràng, dự án trượt rất nhanh thành một mớ code
rối và nợ kỹ thuật cứ thế dồn lại. Tôi cho rằng đây mới là câu hỏi quyết định bạn có nên chọn
Express hay không, chứ không phải mấy dòng benchmark.

Đổi lại, cái được thì rõ. Viết bằng [JavaScript](https://camnangai.com/ky-thuat/javascript-la-gi) thuần nghĩa là client và
server nói cùng một ngôn ngữ, đỡ hẳn khoản chuyển ngữ cảnh khi bạn ôm cả hai đầu. Dựa lưng vào hệ
sinh thái npm khổng lồ, gần như bài toán nào cũng có sẵn package để lắp vào.

## Một ứng dụng Express tối thiểu trông như thế nào?

Khởi tạo một server Express chỉ cần vài dòng:

```javascript
const express = require("express");
const app = express();
const port = 3000;

app.get("/", (req, res) => {
  res.send("Hello World!");
});

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});
```

Đối tượng `app` là thực thể chính, do hàm `express()` tạo ra. Phương thức `app.get` nhận hai tham
số: đường dẫn và một hàm callback xử lý. Callback này nhận hai đối tượng cốt lõi: `req` chứa mọi
thông tin từ phía client, còn `res` dùng để phản hồi.

Khi trình duyệt gửi request đến port 3000 với đường dẫn `/`, Express khớp route rồi chạy callback
tương ứng. Lệnh `res.send` vừa gửi dữ liệu về client, vừa tự thiết lập các header cần thiết và kết
thúc chu kỳ request-response. Nhờ vậy kết nối không bị treo.

Riêng `app.listen` có một thay đổi đáng lưu ý ở Express 5: khi server gặp lỗi, callback bạn truyền
vào sẽ được gọi kèm theo lỗi đó, thay vì lỗi bị ném ra như ở bản 4. Trách nhiệm xử lý chuyển về
phía callback, nên hãy kiểm tra tham số lỗi trước khi hồn nhiên log dòng "đang lắng nghe".

## Middleware: cơ chế cốt lõi của Express

Middleware là các hàm trung gian nằm giữa request và response, những chốt kiểm soát trong luồng xử
lý. Một hàm middleware tiêu chuẩn nhận ba tham số: `req`, `res` và `next`. Nó chạy logic của mình
(xác thực, ghi log, đọc body), rồi hoặc kết thúc chu kỳ bằng một lệnh phản hồi, hoặc gọi `next()` để
chuyển quyền cho hàm kế tiếp trong stack. Bỏ qua cả hai, request sẽ treo vô thời hạn.

![Request đi qua chuỗi hàm middleware (req, res, next) trước khi tới response, với ba nhóm middleware tích hợp sẵn, bên thứ ba và tự viết](https://camnangai.com/articles/expressjs-la-gi/03-vn.webp)

Express phân middleware thành ba nhóm:

1. **Middleware tích hợp sẵn:** Express đóng gói sẵn năm hàm. `express.static` phục vụ file tĩnh,
   `express.json` đọc body dạng JSON, `express.urlencoded` đọc dữ liệu form, cùng `express.raw` và
   `express.text` cho payload dạng Buffer và văn bản.
2. **Middleware bên thứ ba:** cài từ npm, ví dụ `morgan` để ghi log request hay `cookie-parser` để
   đọc cookie.
3. **Middleware tự viết:** phần logic nghiệp vụ riêng của bạn.

Thứ tự khai báo là yếu tố sống còn, vì Express chạy middleware đúng theo trình tự chúng xuất hiện
trong code. Lỗi phổ biến nhất: đặt `express.json()` _sau_ các route handler, thế là `req.body` thành
`undefined` mà không có lấy một dòng log hay cảnh báo nào, và bạn cứ thế ngồi soi xem dữ liệu bốc
hơi ở đâu. Tương tự, đặt error handler lên trên các route thì nó sẽ chẳng bao giờ bắt được lỗi từ
những route đó.

Một middleware ghi log đơn giản trông như sau:

```javascript
app.use((req, res, next) => {
  console.log(`${new Date().toISOString()} - ${req.method} ${req.url}`);
  next();
});
```

## Định tuyến và express.Router

Định tuyến quy định server phản hồi ra sao với từng endpoint, theo từng phương thức HTTP cụ thể: GET,
POST, PUT, DELETE. Express ánh xạ chúng qua `app.METHOD()`. Ngoài ra còn `app.all()`, dùng khi bạn
muốn áp một logic chung cho mọi phương thức tại cùng một đường dẫn, chẳng hạn bắt buộc xác thực.

![Express ánh xạ phương thức HTTP tới đường dẫn qua app.METHOD(), còn express.Router tách từng cụm tính năng thành ứng dụng con gắn vào ứng dụng chính](https://camnangai.com/articles/expressjs-la-gi/04-vn.webp)

Express cho phép trích dữ liệu động qua tham số route. Với route `/users/:id`, giá trị thật nằm ở
`req.params.id`. Đây là nền tảng của mọi API RESTful. Ở Express 5, phần khớp đường dẫn chuyển sang
`path-to-regexp` v8 với cú pháp chặt hơn hẳn: ký tự đại diện phải được đặt tên (`/*splat` thay vì
`/*`), và đoạn tùy chọn dùng cặp ngoặc nhọn `{}` thay cho dấu `?` trước đây. Nếu bạn đang nâng cấp
từ bản 4, đây là chỗ tôi khuyên nên rà lại trước tiên.

Khi ứng dụng lớn dần, `express.Router` gần như bắt buộc. Router hoạt động như một ứng dụng con: bạn
tách logic của từng cụm tính năng (`/users`, `/orders`) ra file riêng, rồi gắn vào ứng dụng chính
bằng `app.use()`. Khi lồng router vào nhau, tham số của route cha mặc định không truyền xuống; thêm
tùy chọn `{ mergeParams: true }` lúc khởi tạo Router để route con đọc được chúng.

## Xử lý lỗi trong Express

Express có sẵn một bộ xử lý lỗi mặc định nằm cuối stack middleware. Lỗi nào phát sinh mà không ai bắt
sẽ rơi vào đó và trả về mã 500. Ở môi trường phát triển, nó kèm luôn stack trace; khi `NODE_ENV` đặt
là `production`, phần stack trace bị lược đi. Đó đúng là hành vi bạn muốn, vì đẩy stack trace về
client là một lỗ hổng bảo mật thực sự.

![Lỗi rơi xuống middleware bốn tham số (err, req, res, next) khai báo cuối stack, rồi tới bộ xử lý lỗi mặc định của Express](https://camnangai.com/articles/expressjs-la-gi/05-vn.webp)

Cải tiến lớn nhất của Express 5 là tự động bắt lỗi từ những Promise bị reject trong handler `async`.
Bạn không còn phải bọc mọi thứ trong `try-catch` rồi gọi `next(err)` thủ công như ở bản 4. Riêng
khoản này thôi đã đủ lý do để nâng cấp. Nhưng với các API kiểu callback cũ như `fs.readFile`, bạn vẫn
phải tự bắt lỗi và đẩy vào `next(err)`.

Một middleware xử lý lỗi tự viết luôn phải có đủ bốn tham số: `(err, req, res, next)`. Thiếu tham số
`err`, Express xem đây là middleware thường và bỏ qua toàn bộ logic xử lý lỗi bạn viết. Nó cũng phải
được khai báo sau cùng, sau tất cả `app.use()` và route. Một chi tiết dễ quên: nếu lỗi xảy ra khi
header đã gửi đi rồi, hãy gọi `next(err)` để nhường lại cho bộ xử lý mặc định đóng kết nối.

## Express 5 khác Express 4 ở đâu?

Express 5 tập trung hiện đại hóa phần lõi và giảm nợ kỹ thuật, chứ không thêm tính năng mới:

1. **Yêu cầu hệ thống:** cần Node.js 18 trở lên.
2. **Loại bỏ phương thức cũ:** `app.del()` bị xóa hẳn, thay bằng `app.delete()`. `req.param()` cũng
   biến mất, buộc bạn truy cập tường minh vào `req.params`, `req.query` hoặc `req.body`.
   `res.sendfile()` đổi thành `res.sendFile()`.
3. **Chuẩn hóa tên phương thức:** `req.acceptsCharset()` thành `req.acceptsCharsets()`, tương tự với
   Encodings và Languages.
4. **Thay đổi về khớp đường dẫn:** ký tự đại diện bắt buộc phải có tên, và dấu `?` không còn dùng
   được trực tiếp trong chuỗi đường dẫn.
5. **Thay đổi MIME type:** file `.js` nay được phục vụ với MIME type `text/javascript` thay vì
   `application/javascript`.
6. **Mặc định mới:** `express.urlencoded` đặt tùy chọn `extended` về `false`, và `express.static.mime`
   không còn được export, dùng package `mime-types` độc lập thay thế.

![So sánh Express 4 và Express 5: các phương thức cũ bị loại bỏ đặt cạnh dạng thay thế mới](https://camnangai.com/articles/expressjs-la-gi/06-vn.webp)

Đội Express cung cấp sẵn bộ codemod tự động hóa phần lớn việc chuyển đổi, chạy qua
`@expressjs/v5-migration-recipe`. Được đến đâu hay đến đó; riêng phần khớp đường dẫn thì vẫn nên tự
soi lại bằng mắt.

## Express có còn được duy trì tốt không?

Có, và rõ rệt hơn nhiều người nghĩ. Năm 2024, Express đạt trạng thái "Impact Project" của OpenJS
Foundation, mức ghi nhận vai trò then chốt của dự án trong hệ sinh thái JavaScript. Technical
Committee được bổ sung tám thành viên mới, trong đó có Blake Embrey, Ulises Gascón và Wes Todd.

Dự án đẩy bảo mật lên thành ưu tiên số một. Đợt kiểm toán bảo mật năm 2024 khiến họ áp dụng OSSF
Scorecard để theo dõi sức khỏe theo thời gian thực. Với các tổ chức còn chạy phiên bản cũ, Express
hợp tác cùng HeroDevs cung cấp gói hỗ trợ dài hạn để tiếp tục vá bảo mật.

Lộ trình 2025–2026, với hậu thuẫn từ Sovereign Tech Fund, xoay quanh ba việc: tự động hóa quy trình
phát hành trên npm để bớt sai sót thủ công, chuyển sang scoped package `@expressjs/` để quản lý hệ
sinh thái gọn hơn, và tối ưu sâu phần lõi. Nhóm kỳ vọng những cải tiến hiệu năng này hoàn tất vào
giữa năm 2026. Với một dự án nhiều năm bị đồn là đã ngủ đông, đó là một quãng hồi sức đáng nể.

## Khi nào nên chọn Express — và khi nào không?

Chọn Express khi bạn cần sự linh hoạt tối đa và muốn kiểm soát chi tiết từng thành phần trong
middleware stack. Nó là lựa chọn tự nhiên cho các API nhẹ, microservice và những dịch vụ trung gian.
Ở những chỗ đó, một framework đồ sộ chỉ làm vướng chân.

![Khi nào nên chọn Express và khi nào không: API nhẹ cần kiểm soát chi tiết đặt cạnh đội đông người cần framework dọn sẵn quy ước](https://camnangai.com/articles/expressjs-la-gi/07-vn.webp)

Đừng chọn Express nếu bạn muốn một framework dọn sẵn mọi thứ, có cấu trúc chuẩn và quy ước rõ ràng
ngay từ đầu để đội đông người khỏi phải tự thiết kế kiến trúc. Express đưa cho bạn quyền tự quyết,
và đi kèm quyền đó là trách nhiệm giữ cho kiến trúc khỏi rối. Nếu đội bạn chưa sẵn sàng nhận phần
trách nhiệm ấy, hãy chọn thứ khác.

## Tài liệu tham khảo

- [Express.js · Node.js web application framework](https://expressjs.com/)
- [Express/Node introduction — MDN](https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Server-side/Express_Nodejs/Introduction)
- [Using middleware · Express.js 5.x](https://expressjs.com/en/5x/guide/using-middleware.html)
- [Routing · Express.js 5.x](https://expressjs.com/en/5x/guide/routing.html)
- [Error Handling · Express.js 5.x](https://expressjs.com/en/5x/guide/error-handling.html)
- [Upgrade to Express v5 · Express.js](https://expressjs.com/en/guide/migrating-5.html)
- [What's New in Express.js v5.0 — Better Stack Community](https://betterstack.com/community/guides/scaling-nodejs/express-5-new-features/)
- [A New Chapter for Express.js: Triumphs of 2024 and an ambitious 2025 · Express.js](https://expressjs.com/en/blog/2025-01-09-rewind-2024-triumphs-and-2025-vision/)
