99 Ngày Spring — Ngày 69: Chuẩn hóa error handling
Client cần biết lỗi nào có thể sửa, lỗi nào có thể thử lại và cách liên hệ log khi sự cố xảy ra. Spring Framework 6 hỗ trợ ProblemDetail cho phản hồi lỗi HTTP. Một hợp đồng lỗi tốt thêm mã lỗi ổn định và correlation ID, đồng thời không lộ stack trace hay dữ liệu nhạy cảm.

1. Phân loại lỗi và mã ổn định
Phân biệt validation 400, không tìm thấy 404, xung đột 409, lỗi phụ thuộc 502/503 và lỗi server 500. Mã như BOOKING_DATE_RANGE là hợp đồng cho máy đọc; detail có thể dịch theo locale. Không gom mọi ngoại lệ thành 200 kèm chuỗi lỗi, vì client và monitoring sẽ hiểu sai.
ProblemDetail p = ProblemDetail.forStatus(409);
p.setTitle("Conflict");
p.setDetail(localizedMessage);
p.setProperty("code", "BOOKING_ALREADY_EXISTS");
p.setProperty("correlationId", correlationId);2. Xử lý tập trung với ControllerAdvice
@RestControllerAdvice ánh xạ ngoại lệ nghiệp vụ sang status và ProblemDetail. Xử lý validation riêng để trả field errors. Giữ handler dự phòng cho lỗi không biết, nhưng log lỗi gốc ở server và chỉ gửi detail chung cho client; tránh log trùng cùng một lỗi ở nhiều tầng.
@RestControllerAdvice
class ApiErrors {
@ExceptionHandler(BookingConflict.class)
ProblemDetail conflict(BookingConflict ex) {
var p = ProblemDetail.forStatus(409);
p.setProperty("code", "BOOKING_ALREADY_EXISTS");
return p;
}
}3. Correlation ID qua request
Nhận hoặc tạo correlation ID ở filter, kiểm tra định dạng và độ dài trước khi dùng header từ client. Đưa ID vào response và MDC log, rồi xóa MDC trong finally. Nếu gọi service khác, truyền ID hoặc trace context có chủ đích. Correlation ID giúp tìm log, nhưng không thay thế trace ID/span ID của hệ thống tracing.
String id = validatedOrNew(request.getHeader("X-Correlation-ID"));
try {
MDC.put("correlationId", id);
response.setHeader("X-Correlation-ID", id);
chain.doFilter(request, response);
} finally { MDC.remove("correlationId"); }4. Kiểm tra hợp đồng lỗi
Gửi request lỗi thật và kiểm tra status, Content-Type, code, detail, field errors và correlation ID. Thử cả vi/en để chắc detail thay đổi mà code không đổi. Xác nhận lỗi 500 không chứa tên class, SQL, token hoặc stack trace. Ghi lại contract cho client và version khi thay đổi ngữ nghĩa mã lỗi.
Cùng một nguyên nhân phải có cùng code ở mọi endpoint.
Log lỗi một lần tại ranh giới phù hợp và gắn ID tra cứu.
ProblemDetail cho khuôn HTTP; code, thông điệp dịch và correlation ID làm lỗi có thể xử lý và điều tra. Ngày 70 nối log với metrics và tracing.
Tài liệu đối chiếu
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-ann-rest-exceptions.html
https://docs.spring.io/spring-boot/3.5/reference/web/servlet.html
Site Admin
Engineer and writer. Building things with TypeScript and distributed systems.
Bình luận (0)
Bạn cần đăng nhập bằng Google để bình luận.
Hãy là người bình luận đầu tiên.


