Bạn đã bao giờ rơi vào cảnh đang hí hửng demo dự án cho khách hàng thì bỗng nhiên server "lăn đùng ra chết" chỉ vì một lỗi nhỏ xíu chưa? Hay tệ hơn, bạn phải lặn ngụp trong hàng tá file code chỉ để tìm xem cái lỗi undefined kia nó phát ra từ đâu vì chỗ nào cũng thấy try-catch rối rắm? Xử lý lỗi (hay còn gọi là Error Handling) không chỉ là việc bắt lỗi để server không sập, mà nó là nghệ thuật giúp hệ thống của bạn tự tin đối mặt với mọi "giông bão" từ phía người dùng.
Đừng biến code thành "bãi chiến trường" với try-catch khắp nơi
Nhiều bạn mới làm quen với Node.js thường có thói quen bọc mọi hàm xử lý trong try-catch. Kết quả là code bị phình to, lặp lại nhàm chán và cực kỳ khó bảo trì. Thay vì làm thủ công như vậy, Express cung cấp một cơ chế cực hay gọi là Middleware xử lý lỗi tập trung. Bạn chỉ cần viết logic bắt lỗi ở một nơi duy nhất, và mọi lỗi xảy ra trong các route sẽ được "đổ" về đây để xử lý.

// Middleware xử lý lỗi cuối cùng trong file app.js
app.use((err, req, res, next) => {
const statusCode = err.statusCode || 500;
res.status(statusCode).json({
status: 'error',
message: err.message || 'Lỗi hệ thống rồi bạn ơi!',
});
});
Bằng cách này, khi có lỗi xảy ra ở bất kỳ đâu, bạn chỉ cần gọi next(err) là xong. Cách làm này giúp code của bạn sạch sẽ hơn rất nhiều, tương tự như việc áp dụng Cách Prettier và ESLint để giữ cho format luôn chuẩn chỉnh vậy.
Mẹo nhỏ: Với Node.js từ phiên bản 16 trở đi, bạn có thể dùng các thư viện như express-async-errors để tự động bắt lỗi trong các hàm async/await mà không cần viết try-catch thủ công nữa.
Phân loại lỗi để không bị "loạn đao pháp"
Không phải lỗi nào cũng giống nhau. Một lập trình viên Backend chuyên nghiệp cần phân biệt được hai loại lỗi chính: Lỗi vận hành (Operational Errors) và Lỗi lập trình (Programmer Errors). Lỗi vận hành là những thứ ta có thể dự đoán như: sai mật khẩu, hết hạn token, hay database bị ngắt kết nối. Còn lỗi lập trình là do ta viết code ẩu, ví dụ như gọi một thuộc tính của null.
Hãy tạo một Class riêng để quản lý các lỗi này. Việc này giúp bạn kiểm soát được statusCode và thông báo trả về cho người dùng một cách nhất quán nhất.
class AppError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
this.isOperational = true; // Đánh dấu đây là lỗi ta đã kiểm soát
Error.captureStackTrace(this, this.constructor);
}
}
Việc phân loại rõ ràng giúp bạn kết hợp cực tốt với Cách API Security để không vô tình tiết lộ những thông tin nhạy cảm của server ra bên ngoài khi có sự cố xảy ra.
Ghi nhật ký (Logging) - Đôi mắt của lập trình viên Backend
Khi server chạy trên môi trường thực tế (Production), bạn không thể ngồi canh màn hình terminal để xem console.log được. Lúc này, bạn cần một hệ thống ghi nhật ký (Logging) chuyên nghiệp như Winston hoặc Morgan. Chúng giúp bạn lưu lại mọi diễn biến của server vào file hoặc gửi lên các dịch vụ quản lý tập trung.
- Level lỗi: Phân chia rõ ràng đâu là Info (thông tin), Warn (cảnh báo) và Error (lỗi nghiêm trọng).
- Thời điểm: Ghi chính xác thời gian xảy ra lỗi để đối chiếu với hành vi người dùng.
- Context: Lưu lại các thông tin như ID người dùng hoặc URL bị lỗi để dễ dàng tái hiện lại.
Khi đã có hệ thống Error Handling và Logging xịn sò, bạn có thể tự tin kết hợp với Cách PM2 giúp server Node.js của bạn "bất tử". PM2 sẽ lo việc restart nếu server sập, còn Error Handling sẽ lo việc server không bao giờ sập vì những lý do ngớ ngẩn. Bạn có thể tham khảo thêm tài liệu chính thức về Xử lý lỗi trong Express để hiểu sâu hơn về các kỹ thuật nâng cao.
Hệ thống xử lý lỗi tốt giống như một tấm lưới bảo hiểm, giúp bạn an tâm hơn khi triển khai dự án lớn. Nhưng liệu bạn đã bao giờ tự hỏi, làm sao để kiểm tra xem tấm lưới đó có thực sự hoạt động trước khi đưa cho người dùng thật hay chưa?
Ghé thăm DIA DEMY để cập nhật thêm nhiều kiến thức Backend thực chiến nhé!




Vui lòng đăng nhập để bình luận.