Họ đang đo gì
Bạn có coi mã trạng thái là một phần của hợp đồng API hay chỉ là con số trả về cho đủ.
Trả lời ngắn~30 giây
401 Unauthorized nghĩa là chưa xác thực hoặc token không hợp lệ — tên gọi lịch sử bị đặt sai, nó nói về authentication. 403 Forbidden nghĩa là đã biết bạn là ai nhưng bạn không có quyền, và gửi lại token khác cũng vô ích. 404 dùng khi tài nguyên không tồn tại — hoặc cố ý dùng thay cho 403 khi việc thừa nhận tài nguyên tồn tại đã là rò rỉ thông tin.
Giải thích sâu
Chỗ 404 thay cho 403 đáng nói kỹ: nếu /orders/123 trả 403 cho người không sở hữu đơn đó, kẻ tấn công quét id và biết được đơn nào tồn tại — một dạng liệt kê tài nguyên. Trả 404 cho cả hai trường hợp khiến hai kịch bản không phân biệt được. Đánh đổi là log của bạn phải phân biệt được, nếu không thì đội hỗ trợ mất khả năng chẩn đoán.
Nhóm 4xx và 5xx chia trách nhiệm chứ không chia mức nghiêm trọng: 4xx nghĩa là “yêu cầu này sai, gửi lại y hệt cũng sẽ sai”, 5xx nghĩa là “phía tôi hỏng, thử lại có thể được”. Sự phân chia này quan trọng vì client và cả hạ tầng dựa vào nó để quyết định retry — trả 500 cho một body sai định dạng khiến client retry mãi một yêu cầu không bao giờ thành công.
Vài mã ít dùng mà rất đáng dùng: 409 Conflict cho xung đột trạng thái (khoá lạc quan thất bại), 422 khi cú pháp đúng nhưng nghiệp vụ sai, 429 kèm Retry-After cho giới hạn tần suất, và 503 kèm Retry-After khi bạn đang quá tải. Ba cái sau cho client biết PHẢI LÀM GÌ, chứ không chỉ biết là hỏng.
Câu hỏi tiếp theo họ sẽ hỏi
?200 kèm {"error": …} thì sao?
Nó phá mọi thứ ở tầng dưới: proxy cache lưu lại lỗi, dashboard báo tỷ lệ lỗi 0%, và client phải bóc body mới biết. Nếu bắt buộc phải làm vậy vì lý do lịch sử thì ít nhất đừng để nó được cache.
Trả lời thế này là mất điểm
- Trả 200 cho mọi thứ và đặt mã lỗi thật trong body. Rất phổ biến, và nó vô hiệu hoá quan sát hệ thống.