| domain | contrib |
|---|---|
| title | static page github api 403 rate limit |
| verification | metadata-normalized |
| {"title" | 静态页面调用外部 API 的容错设计原则", "domain": "frontend", "tags": ["api", "rate-limit", "static-site", "error-handling", "fault-tolerance"], "domain_expert": "unknown"} |
| created | 2026-07-06 |
| source | unknown |
纯静态页面(无后端代理,HTML + JS 直接部署在 CDN/GitHub Pages 上)需要通过浏览器端 JavaScript 直接调用第三方 API。这种架构面临几个固有风险:
- 限流硬限制:未认证请求通常有严格的速率限制(如 GitHub REST API 60 req/hour)
- 请求永久挂起:没有超时控制的 fetch 在网络故障时永远不会 resolve
- 错误扩散:一个接口的失败通过 try/catch 或 Promise 链传播,连带阻断其他无关功能
- 无中间层缓冲:不能使用 API key、缓存代理或请求合并等后端手段
浏览器 fetch 默认没有超时。一个慢请求可以永久挂起页面功能。
async function fetchWithTimeout(url, timeoutMs = 8000) {
const ctrl = new AbortController();
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
try {
const r = await fetch(url, { signal: ctrl.signal });
clearTimeout(timer);
if (!r.ok) throw new Error(`HTTP ${r.status}`);
return r.json();
} catch (e) {
clearTimeout(timer);
throw e;
}
}使用 Promise.all 时,任何一个 promise reject 会导致整体失败。改为每个请求独立 catch:
const [dataA, dataB] = await Promise.all([
fetchWithTimeout(urlA).catch(() => null),
fetchWithTimeout(urlB).catch(() => null),
]);
// dataA 失败不影响 dataB 的结果不要用一个大的 try/catch 包裹多个功能模块:
// ❌ 错误:loadA 抛异常则 loadB、loadC 都不执行
try {
await loadA();
await loadB();
await loadC();
} catch (e) { /* 只捕获一个,丢失两个 */ }
// ✅ 正确:各自独立执行
loadA().catch(() => {});
loadB().catch(() => {});
loadC().catch(() => {});不要把原始错误信息(TypeError: Failed to fetch、HTTP 403)直接展示给用户:
// 区分常见的错误类型
if (e instanceof TypeError && e.message.includes('aborted')) {
return '请求超时,请检查网络后重试';
}
if (e.message?.includes('403')) {
return 'API 频率限制,请稍后刷新重试';
}
return '数据加载失败,已使用缓存显示';- 单个接口超时不影响其他接口的展示
- 触发限流时显示友好提示而非白屏或裸错误
- 所有功能模块各自独立加载、独立容错
- 网络恢复后刷新页面即可正常使用
静态页面直接消费第三方 API 时,容错不是可选项而是架构必选项。因为没有后端中间层兜底,每个接口调用都直接暴露在浏览器环境下:
- 任何外部请求都可能失败——网络断开、限流、服务端故障,不是 if 而是 when
- 不要用 try/catch 包裹多个逻辑块——一个失败不应该连带其他功能一起失效
- 非关键数据失败不应阻断关键数据展示——统计数字和主要内容应该互不影响
- 没有超时的 fetch 是永久挂起的隐患——即使请求本地 JSON 文件也应有超时保护
- 如果项目频繁遇到限流,考虑引入 GitHub Actions 定时缓存 + 静态 JSON 的 hybrid 架构,或使用代理后端
English:
lessons/en/static-page-github-api-fault-tolerance.md