Hiệu năng, cache, giới hạn và lỗi
Đọc trang này trước khi đưa trang web lên chạy thật.
Gọi từ trình duyệt (CORS)
Mọi đường dẫn dưới /v2/public/cms/ trả về Access-Control-Allow-Origin: * cho mọi tên miền, nên trang web của bạn gọi thẳng từ trình duyệt được, không cần máy chủ trung gian.
Điều kiện:
- Không gửi cookie hay thông tin đăng nhập: dùng
credentials: 'omit'(hoặc mặc định củafetchkhi khác tên miền). API không cho phép kèm thông tin đăng nhập. - Không thêm header nào (kể cả
Authorization,Content-Typehay headerX-…của bạn). Một yêu cầuGETkhông header là «simple request»: trình duyệt gửi thẳng, không cần yêu cầuOPTIONStrước. Thêm header là thêm một vòng mạng cho mỗi lần tải. - Chỉ các phương thức
GET,HEADvàPOST(cho tín hiệu lượt xem). - Các header giới hạn tần suất (
x-ratelimit-*) không đọc được từ JavaScript khi gọi khác tên miền; chỉ mã trạng thái429là đọc được.
Bộ đệm (cache)
Phản hồi thành công của ba đường dẫn GET có:
Cache-Control: public, s-maxage=60, max-age=0, must-revalidate
- CDN giữ một bản cho mỗi URL tối đa 60 giây. Khi nhân sự lưu thay đổi, hệ thống chủ động xóa các URL bị ảnh hưởng khỏi CDN, nên thường thay đổi hiện ra ngay; 60 giây là mức trễ tối đa khi việc xóa không tới được.
- Trình duyệt không dùng lại bản cũ mà luôn hỏi lại (CDN trả lời nhanh).
- Phản hồi lỗi (
4xx,5xx) luôn cóCache-Control: private, no-storevà không bao giờ được lưu.
Việc xóa chủ động chỉ biết tới một cách viết URL. Để trang của bạn nhận thay đổi ngay:
- Viết tham số theo đúng thứ tự
locale, category, tag, q, sort, page, limit, không thêm tham số khác. - Luôn ghi rõ
locale, kể cả với/site. - Với danh sách, chỉ trang 1 được xóa chủ động; các trang sau, và mọi URL tìm kiếm (
q), có thể trễ tới 60 giây.
Giữ đúng một cách viết URL cũng giúp mọi người đọc dùng chung một bản trong CDN.
Giới hạn tần suất
Giới hạn tính theo địa chỉ của máy gọi:
| Đường dẫn | Giới hạn |
|---|---|
GET /site, GET /entries, GET /entries/{entrySlug} | 20 yêu cầu / 10 giây, 50 yêu cầu / 10 giây (chung), 120 yêu cầu / 60 giây |
POST /entries/{entrySlug}/view | 5 yêu cầu / 10 giây, 30 yêu cầu / 60 giây |
Vượt giới hạn nhận 429 với errorCode: "RATE_LIMITED". Mỗi phản hồi có các header x-ratelimit-limit-*, x-ratelimit-remaining-*, x-ratelimit-reset-* (giây) cho các mức short, medium, long.
Với người đọc gọi từ trình duyệt, mỗi người có giới hạn riêng nên hiếm khi chạm tới. Rủi ro thật nằm ở máy chủ của bạn: khi dựng trang tĩnh, dựng trang phía máy chủ hay chạy một proxy, mọi yêu cầu đều đi từ một địa chỉ.
- Khi dựng trang tĩnh: gọi tuần tự, khoảng 1 yêu cầu mỗi giây (dưới 120 yêu cầu/phút), dùng
limit=100để giảm số trang, và thử lại sau vài giây khi gặp429. - Khi dựng phía máy chủ theo từng lượt truy cập: đặt bộ đệm của riêng bạn (ví dụ 60 giây) trước API. Không chuyển thẳng mỗi lượt truy cập thành một yêu cầu tới API.
async function getWithRetry(url: string, tries = 4): Promise<Response> {
for (let i = 0; ; i++) {
const res = await fetch(url, { credentials: 'omit' })
if (res.status !== 429 || i === tries - 1) return res
await new Promise((r) => setTimeout(r, 2000 * 2 ** i)) // 2 s, 4 s, 8 s
}
}
Xử lý lỗi
Dạng thân lỗi và bảng mã: Tham chiếu API, Dạng lỗi. Danh sách cần làm:
-
404trên một entry → trang «Không tìm thấy» của bạn (với SSR, trả mã404thật). Với ngôn ngữ phụ, cân nhắc thử lại ở ngôn ngữ chính (xem). -
404trên/site→ mã trang web sai, trang web bị tắt, hoặc ngôn ngữ chưa bật. Đây là lỗi cấu hình, đừng hiện cho người đọc như một trang trống: dùng nội dung dự phòng và ghi log. -
info: null→ nhân sự chưa nhập thông tin; dùng tên, địa chỉ dự phòng mà bạn dựng sẵn. -
400→ lỗi trong mã của bạn (tham số sai,limitngoài danh sách). Không thử lại. -
429,5xx, lỗi mạng → thử lại có giãn cách; trong lúc chờ, giữ nội dung đang hiện hoặc hiện một khung «Không tải được, thử lại». - Danh sách rỗng (
data: []) → hiện «Chưa có bài viết», nhất là với «Đọc nhiều» của một trang web mới. - Trường có thể thiếu →
cover,excerpt, các khóa trongmeta, các chuỗi tronginfo. - Kiểm tra dữ liệu nhận về trước khi dùng (kiểu của từng trường), và lọc lại
bodyHtmltrước khi chèn vào trang. - Tín hiệu lượt xem không bao giờ được làm hỏng trang: bỏ qua mọi lỗi.
Kiến trúc khuyến nghị
| Cách làm | Hợp với | Lưu ý |
|---|---|---|
| Gọi từ trình duyệt (SPA) | Trang nhỏ, đội ít người | Đơn giản nhất; CORS đã mở. Nội dung hiện sau khi JavaScript chạy, kém hơn cho SEO. |
| Trang tĩnh (SSG) + gọi từ trình duyệt cho phần động | Phần lớn trang web giáo xứ | Dựng sẵn vỏ trang, menu, thông tin liên hệ, các bài hiện có; tải danh sách mới nhất, tìm kiếm và «Đọc nhiều» từ trình duyệt. Dựng lại định kỳ (ví dụ mỗi giờ) để bài mới có trang tĩnh. Giữ một đường dự phòng phía trình duyệt cho slug chưa có lúc dựng. |
| Dựng phía máy chủ (SSR) có bộ đệm | Trang lớn, cần SEO tốt cho mọi bài | Đặt bộ đệm 60 giây của riêng bạn, tôn trọng giới hạn tần suất, trả 404/301 thật cho slug không có/slug cũ. |
Dù chọn cách nào:
- Đặt địa chỉ gốc API và mã trang web vào biến cấu hình, không viết cứng rải rác.
- Gom mọi lệnh
fetchtới API vào một hàm (đúngcredentials, không header, đúng thứ tự tham số). - Tín hiệu lượt xem chỉ gửi từ trình duyệt, không bao giờ lúc dựng trang.