资源请求优化
1. 缓存策略
核心原则:HTML 用协商缓存(保证拿到最新入口),JS/CSS/图片用强缓存(文件名带 hash)。
HTML(入口)
Cache-Control: no-cache → 每次请求都验证是否过期(协商缓存)
JS / CSS / 图片(带 hash 文件名)
Cache-Control: max-age=31536000 → 永久强缓存
文件内容变了 → 文件名变了 → 浏览器视为新资源 → 重新下载
带 hash 的文件名(
app.3f8a2b.js)是关键——内容变了文件名才变,内容没变直接命中缓存,两全其美。
2. 压缩传输(Gzip / Brotli)
服务端对文本资源(HTML、JS、CSS)启用压缩,体积通常减少 60%~80%。
# Nginx 开启 Brotli(压缩率优于 Gzip,现代浏览器均支持)
brotli on;
brotli_types text/html text/css application/javascript;
# 或退回 Gzip(兼容性更广)
gzip on;
gzip_types text/html text/css application/javascript;
| 算法 | 压缩率 | 速度 | 兼容性 |
|---|---|---|---|
| Brotli | 更高 | 略慢 | 现代浏览器 |
| Gzip | 较高 | 快 | 全部 |
图片(JPEG/PNG/WebP)已自带压缩,不要再套 Gzip,反而增大体积。
3. HTTP/2
多路复用、头部压缩、二进制分帧,详见 HTTP 优化#HTTP2.0。
开启后可废弃以下旧优化手段:
雪碧图(HTTP/2 多路复用下小请求开销可忽略)域名分片(HTTP/1.x 绕过 6 个连接限制的技巧,HTTP/2 不再需要)
4. Resource Hints
提前告知浏览器"接下来需要什么",利用空闲时间提前准备。
dns-prefetch — 提前解析 DNS
<!-- 全局开启(HTTPS 页面默认关闭 a 标签的 DNS 预解析,此行重新开启) -->
<meta http-equiv="x-dns-prefetch-control" content="on">
<!-- 对指定域名提前解析 -->
<link rel="dns-prefetch" href="//cdn.example.com">
适用:即将跳转的域名、第三方资源域名、CDN 域名
preconnect — 提前建立连接
在 DNS 解析基础上,还完成 TCP 握手 + TLS 握手。
<link rel="preconnect" href="//cdn.example.com">
preconnect比dns-prefetch更激进,不要滥用——浏览器同时维持的连接数有限。 只对确定会用到的关键域名使用。
preload — 当前页面高优先级资源
立即下载并缓存,不执行,等到 HTML 解析到对应标签时直接使用缓存。
<!-- 提前加载当前页面的关键字体、首屏图片、关键 JS -->
<link rel="preload" as="font" href="/fonts/Inter.woff2" crossorigin>
<link rel="preload" as="image" href="/img/hero.webp">
<link rel="preload" as="script" href="/js/critical.js">
适用:首屏必须的资源,避免渲染阻塞
prefetch — 未来页面低优先级资源
浏览器空闲时下载,供下次导航使用。
<link rel="prefetch" as="script" href="/js/about-page.js">
Vue Router / React Router 的路由懒加载自动生成此标签:
// 路由配置
{ component: () => import('./views/About.vue') }
// 构建后自动产出:<link rel="prefetch" href="about.chunk.js">
prerender — 提前渲染整个页面(谨慎使用)
<link rel="prerender" href="/next-page.html">
⚠️
prerender在 Chrome 中已废弃,现代浏览器推荐使用 Speculation Rules API:<script type="speculationrules"> { "prerender": [{ "urls": ["/next-page"] }] } </script>
5. 避免过多重定向
每次重定向都是一次额外的 HTTP 往返(1 RTT),多级重定向累积延迟明显。
❌ http://example.com → https://example.com → https://www.example.com(2次重定向)
✅ http://example.com → https://www.example.com(合并为1次)
6. CDN
CDN 将静态资源分发到离用户最近的节点,降低传输延迟。
CDN 加载失败兜底
CDN 解析可能因地区、运营商等原因失败,需要监听并重试:
window.addEventListener('error', (e) => {
const target = e.target
// 过滤资源加载错误(区别于 JS 运行时错误)
if (target instanceof HTMLScriptElement || target instanceof HTMLLinkElement) {
const failed = target.src || target.href
console.error('资源加载失败:', failed)
// 策略1:换备用 CDN 域名重试
const fallbackUrl = failed.replace('cdn1.example.com', 'cdn2.example.com')
if (target instanceof HTMLScriptElement) {
const script = document.createElement('script')
script.src = fallbackUrl
document.head.appendChild(script)
}
// 策略2:刷新页面(限制次数,防止死循环)
const retryCount = Number(sessionStorage.getItem('cdn_retry') || 0)
if (retryCount < 2) {
sessionStorage.setItem('cdn_retry', retryCount + 1)
window.location.reload()
}
}
}, true) // 必须用捕获阶段,资源错误不冒泡
7. SSR / SSG
SSR(服务端渲染)
服务端实时渲染 HTML,客户端直接得到有内容的页面。
优点:首屏快、SEO 友好、不依赖客户端设备性能 缺点:服务端压力大,大流量下成本高、扩容复杂
适用:内容实时变化(新闻、电商详情、社交动态)
SSG(静态生成)
构建时生成所有页面的静态 HTML,部署到 CDN 直接返回。
优点:极快(CDN 直出)、零服务器压力、SEO 最佳 缺点:内容更新需要重新构建
适用:内容相对固定(博客、文档、官网落地页)
优先级总结
必做(收益大,成本低):
✅ 开启 Gzip / Brotli 压缩
✅ 静态资源强缓存(文件名带 hash)
✅ 使用 CDN 分发静态资源
✅ HTTP/2
按需(具体场景):
✅ preconnect(关键第三方域名)
✅ preload(首屏关键资源)
✅ prefetch(路由懒加载)
✅ SSR/SSG(SEO 或首屏性能要求高)