跳到主要内容

CDN / 静态资源故障容灾

场景

CDN 服务故障或某个静态资源加载失败,导致页面白屏或功能异常。如何设计容灾方案?

分析思路

资源加载失败的检测

全局资源错误监听
window.addEventListener('error', (e) => {
const target = e.target as HTMLElement;
if (target?.tagName) {
const src = (target as HTMLScriptElement).src
|| (target as HTMLLinkElement).href
|| (target as HTMLImageElement).src;

console.error(`资源加载失败: ${target.tagName} ${src}`);
handleResourceError(target.tagName, src);
}
}, true); // 捕获阶段

容灾方案

方案 1:多 CDN 备份切换

script 加载失败自动切换 CDN
const CDN_LIST = [
'https://cdn1.example.com',
'https://cdn2.example.com',
'https://cdn3.example.com',
];

function loadScriptWithFallback(path: string, cdnIndex = 0): Promise<void> {
if (cdnIndex >= CDN_LIST.length) {
return Promise.reject(new Error(`所有 CDN 均不可用: ${path}`));
}

return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = `${CDN_LIST[cdnIndex]}${path}`;
script.onload = () => resolve();
script.onerror = () => {
console.warn(`CDN ${cdnIndex} 失败,尝试 CDN ${cdnIndex + 1}`);
loadScriptWithFallback(path, cdnIndex + 1).then(resolve, reject);
};
document.head.appendChild(script);
});
}

方案 2:Service Worker 缓存兜底

sw.ts — 缓存关键资源
const CACHE_NAME = 'app-v1';
const CRITICAL_ASSETS = ['/index.html', '/main.js', '/style.css'];

self.addEventListener('install', (event: ExtendableEvent) => {
event.waitUntil(
caches.open(CACHE_NAME).then((cache) => cache.addAll(CRITICAL_ASSETS))
);
});

self.addEventListener('fetch', (event: FetchEvent) => {
event.respondWith(
fetch(event.request).catch(() => {
// 网络失败时从缓存读取
return caches.match(event.request).then((cached) => {
return cached || new Response('资源不可用', { status: 503 });
});
})
);
});

方案 3:HTML 内联关键资源

关键 CSS 内联到 HTML
<head>
<!-- 关键 CSS 内联,不依赖外部资源 -->
<style>
body { margin: 0; font-family: system-ui; }
.loading { display: flex; justify-content: center; align-items: center; height: 100vh; }
</style>
</head>

常见面试问题

Q1: CDN 挂了怎么办?

答案

  • 检测window.addEventListener('error') 捕获资源加载失败
  • 自动切换:多 CDN 备份,失败时自动切换域名
  • 缓存兜底:Service Worker 缓存关键资源
  • 降级方案:CDN 全挂时展示本地缓存或静态兜底页面
  • 监控告警:CDN 资源加载失败率超阈值自动告警

相关链接