Trang trạng thái HTTP
404, 500, bảo trì, mất mạng: khi cả trang không hiện được, nói rõ chuyện gì xảy ra, chỉ một việc nên làm tiếp và tự khôi phục khi có thể, trong cùng bố cục với màn chờ khởi động.
Khi nào cần trang riêng
Trang trạng thái thay cả vùng nội dung chính, nên chỉ dùng khi cả route không hiện được: đường dẫn không có trang, không có quyền, máy chủ lỗi, mất mạng lúc mở trang. Một phần của trang lỗi thì báo ngay tại phần đó, phần còn lại vẫn dùng được.
| Tình huống | Dùng |
|---|---|
| Cả route không render được | Trang trạng thái |
| Một vùng tải lỗi (bảng, biểu đồ) | ErrorState trong vùng đó, có nút thử lại |
| Gửi form lỗi | Lỗi ở từng field hoặc MessageBar; giữ nguyên dữ liệu đã nhập |
| Lỗi ngắn, tự hết | Toast hoặc MessageBar |
Phòng thử
Mười một trạng thái trong cùng bố cục với màn chờ khởi động. Đổi kiểu số (Kanji / Latin), chạy lại, hoặc xem toàn màn hình rồi chuyển trạng thái bằng nút trước / sau.
Không tìm thấy trang
Không có trang ở đường dẫn này.
Danh mục trạng thái
| Mã | Tiêu đề | Khi nào | Hành động chính |
|---|---|---|---|
| 400 | Yêu cầu không hợp lệ | Tham số trong URL hoặc dữ liệu gửi lên sai dạng, người dùng không sửa được tại chỗ. | Quay lại |
| 401 | Cần đăng nhập | Chưa đăng nhập hoặc phiên đã hết hạn. | Đăng nhập |
| 403 | Không có quyền truy cập | Đã đăng nhập nhưng thiếu quyền. | Xin quyền truy cập |
| 404 | Không tìm thấy trang | Không có trang ở đường dẫn này. | Tìm kiếm |
| 410 | Trang này đã bị gỡ | Trang bị gỡ có chủ đích; biết chỗ thay thế thì dẫn tới đó. | Tới trang mới |
| 429 | Bạn thao tác hơi nhanh | Vượt giới hạn số yêu cầu; thời gian chờ lấy từ header Retry-After. | Thử lại |
| 500 | Máy chủ gặp lỗi | Lỗi không lường trước ở máy chủ, kể cả 502 từ cổng trung gian. | Thử lại |
| 503 | Đang bảo trì | Bảo trì có kế hoạch hoặc quá tải tạm thời; có Retry-After thì đếm ngược. | Tải lại |
| 504 | Máy chủ phản hồi quá lâu | Hết thời gian chờ ở máy chủ (504) hoặc ở trình duyệt (408). | Thử lại |
| Ngoại tuyến | Không có kết nối mạng | Trình duyệt mất mạng hoặc yêu cầu lỗi mạng; nghe sự kiện online để tự thử lại. | Thử lại |
| Bản mới | Đã có phiên bản mới | Nạp file JS lỗi sau một lần deploy (tab mở từ trước, tên file đã đổi). | Tải lại |
Viết nội dung
Tiêu đề nói chuyện gì xảy ra bằng lời thường (“Không tìm thấy trang”), mô tả nói vì sao nếu biết và người dùng làm được gì tiếp. Mã nằm ở dòng nhỏ phía trên tiêu đề cho ai cần báo lỗi, không bao giờ là chữ duy nhất trên trang.
Không đổ lỗi cho người dùng, không đùa khi họ vừa mất việc đang làm, không in stack trace. Mã để tra lỗi (7f3a-91c2) là chữ thường, chọn và sao chép được.
Mỗi trang có đúng một hành động chính; hành động phụ là lối ra an toàn như về trang chủ hay đổi tài khoản.
Logo & mã viết dọc
Logo ở góc đổi theo trạng thái: thiếu một cánh khi không tìm thấy trang, rụng hết khi trang đã bị gỡ, còn là nụ khi cần đăng nhập hoặc xin quyền, mực đứt khi máy chủ lỗi, nhạt khi hết thời gian chờ, chỉ còn vệt mờ khi mất mạng. Ở 429 và 503, nét cọ đầy dần theo thời gian chờ; hết giờ thì hoa nở cùng lúc nút Thử lại bật.
Kiểu Kanji: mã viết dọc ở mép như màn chờ, đọc từng chữ số (四〇四); trạng thái không có mã dùng chữ: 圏外 (ngoài vùng phủ sóng) khi mất mạng, 新版 khi có bản mới. Kiểu Latin cho sản phẩm không dùng chữ Hán: mã nằm ngang, nét mảnh ở góc trên; trạng thái không có mã thì để trống góc đó.
Tự khôi phục
Trạng thái tạm thời phải tự hết: đếm ngược theo Retry-After rồi bật nút, nghe sự kiện online để thử lại khi có mạng, nạp file JS lỗi sau deploy thì mời tải lại. Đăng nhập xong (401) thì đưa người dùng về đúng trang họ định mở.
// 429 / 503: thời gian chờ lấy từ header, không đoán
const wait = Number(response.headers.get("Retry-After")) || 30;
// Mất mạng: thử lại khi trình duyệt báo có mạng
window.addEventListener("online", retry, { once: true });
// Bản mới: file JS của route không còn sau một lần deploy
const Settings = lazy(() => import("./pages/Settings").catch(() => ({ default: NewVersionPage })));Trang 404 cần trả mã 404 thật và có noindex, để công cụ tìm kiếm không lập chỉ mục một trang trông như bình thường. Host tĩnh (GitHub Pages) chỉ trả được 404.html; 500 và 503 khi đó do app tự hiện.
Khả năng tiếp cận
Tiêu đề là h1 nói tên trạng thái; chuyển trang phía client thì đưa focus tới h1 và cập nhật document.title. Mã viết dọc là trang trí (aria-hidden); mã đọc được nằm ở dòng phía trên tiêu đề.
Đếm ngược báo qua live region polite theo từng quãng (10 giây), không phải mỗi giây. Không tự tải lại mà không nói trước. Khi giảm chuyển động, nét cọ có sẵn và cánh hoa nằm sẵn dưới đất thay vì rơi.
Nên & không nên
- Nói chuyện gì xảy ra bằng lời thường, kèm mã ở dòng phụ.
- Một hành động chính, một lối ra an toàn.
- Đếm ngược theo Retry-After, thử lại khi có mạng.
- Trả mã HTTP thật và noindex cho trang 404.
- Chuyển đường dẫn lạ về trang chủ như không có gì xảy ra.
- Chỉ hiện “404” hay “Error” mà không giải thích.
- In stack trace hoặc thông báo kỹ thuật cho người dùng.
- Tự tải lại liên tục khi máy chủ vẫn đang lỗi.