API trả về 404 nhưng đoạn catch không chạy, giao diện vẫn cố hiển thị dữ liệu rồi báo lỗi ở một dòng khác. Đây là tình huống dễ gặp khi coi một promise được hoàn thành là bằng chứng thao tác HTTP đã thành công. Với fetch, cần kiểm tra từng lớp kết quả trước khi sử dụng dữ liệu.
1. Nhận được phản hồi khác với HTTP thành công
Theo hướng dẫn Fetch của MDN, một HTTP status lỗi như 404 không tự khiến promise của fetch bị reject. Hãy kiểm tra response.ok, thuộc tính đúng khi status nằm trong khoảng 200–299.
const response = await fetch('/api/profile');
if (!response.ok) {
throw new Error('HTTP ' + response.status);
}
const profile = await response.json();
Trong ví dụ này, chính ứng dụng chủ động ném lỗi HTTP. Nếu đặt toàn bộ đoạn mã trong try/catch, lỗi đó mới được đưa đến nhánh catch tương ứng. Đường dẫn API là minh họa, không phải endpoint được bảo đảm tồn tại trên mọi website.
2. Tách ba lớp lỗi khi chẩn đoán
- Không lấy được phản hồi sử dụng được: có thể liên quan mạng, chính sách trình duyệt hoặc yêu cầu bị hủy. Không nên gán mọi trường hợp thành “server trả 500”.
- Phản hồi HTTP ngoài phạm vi chấp nhận: đã có status để quyết định cách xử lý theo hợp đồng API.
- Đọc hoặc kiểm tra body thất bại: status thành công nhưng body có thể không phải JSON hợp lệ hoặc không có cấu trúc mong muốn.
Ví dụ một middleware chuyển hướng sang trang đăng nhập có thể dẫn đến HTML cuối cùng thay vì JSON mong đợi. Khi đó, hãy xem URL cuối, status, Content-Type và body trong Network của DevTools; chỉ đọc dòng thông báo lỗi JSON thường chưa đủ để tìm nguyên nhân.
3. Một hàm đọc JSON có phạm vi rõ ràng
Hàm dưới đây dành cho endpoint GET có hợp đồng trả JSON ở phản hồi thành công. Nó không phải client chung cho tải file, HEAD hoặc API trả body rỗng.
class HttpError extends Error {
constructor(status) {
super('HTTP ' + status);
this.name = 'HttpError';
this.status = status;
}
}
async function readJson(url) {
const response = await fetch(url, {
headers: { Accept: 'application/json' }
});
if (!response.ok) {
throw new HttpError(response.status);
}
return await response.json();
}
async function loadProfile() {
try {
const profile = await readJson('/api/profile');
// Kiem tra schema cua profile truoc khi render.
return profile;
} catch (error) {
if (error instanceof HttpError) {
console.warn('Profile request failed:', error.status);
} else {
console.warn('Could not read profile data');
}
throw error;
}
}
Header Accept thể hiện định dạng client mong muốn, không bắt server phải trả JSON. Hàm không đọc body của phản hồi HTTP lỗi; đây là lựa chọn có chủ đích để giữ ví dụ đơn giản. Nếu API có thông báo lỗi có cấu trúc, cần thêm một bước đọc và kiểm tra riêng, không giả định mọi trang lỗi đều là JSON.
Đoạn catch ghi nhận loại lỗi rồi ném lại. Thành phần gọi loadProfile vẫn phải xử lý promise thất bại và cập nhật trạng thái giao diện; không gọi mà bỏ quên nhánh lỗi. Ví dụ cũng chưa có timeout, hủy yêu cầu hoặc kiểm tra schema.
4. Không biến mọi thất bại thành dữ liệu rỗng
Trả về một mảng rỗng trong catch có thể khiến người dùng hiểu rằng tài khoản chưa có dữ liệu, dù thực tế API đang lỗi. Thiết kế ít nhất ba trạng thái riêng: đang tải, tải thành công và tải thất bại. “Không có kết quả” thuộc nhánh thành công với dữ liệu hợp lệ.
Với 204, không gọi json một cách máy móc: nếu hợp đồng cho phép không có body, xử lý trạng thái đó riêng. Nếu endpoint bắt buộc trả hồ sơ JSON, body rỗng là vi phạm hợp đồng cần báo lỗi. Việc parse JSON thành công cũng chưa chứng minh các trường tên, ID hoặc danh sách có kiểu đúng.
5. Checklist kiểm thử trước khi dùng thật
- 200 với JSON hợp lệ và đúng cấu trúc: hiển thị thành công.
- 200 với HTML hoặc JSON sai cú pháp: hiển thị lỗi đọc dữ liệu.
- 200 với JSON đúng cú pháp nhưng sai schema: không render như dữ liệu hợp lệ.
- 404 hoặc 500: đi vào nhánh HTTP lỗi, không phụ thuộc fetch tự reject.
- 204: xử lý theo hợp đồng endpoint, không mặc định là một object rỗng.
- Mất kết nối hoặc hủy request: không hiển thị HTTP status tự suy đoán.
Không đưa toàn bộ body lỗi, token hoặc thông tin cá nhân vào log. Nếu cần thử lại, thiết kế chính sách riêng theo loại thao tác; đừng tự động gửi lại mọi request, đặc biệt là request ghi dữ liệu.
Kết luận: Hãy tách việc nhận phản hồi, kiểm tra status, đọc body và xác thực cấu trúc. catch là nơi xử lý lỗi được ném ra, không phải bộ kiểm tra HTTP tự động.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.