欢迎光临
我们一直在努力

前端 CDN 缓存策略调优:静态资源、HTML 与 API 分层设计

前端 CDN 缓存策略调优:静态资源、HTML 与 API 分层设计

一、改了静态资源,用户看到的还是旧页面

前端缓存配置三大常见错误:

  • HTML 和 JS 用了同一种缓存策略
  • 静态资源没做 hash,导致强制缓存后更新困难
  • API 响应被 CDN 错误缓存
  • 这三个错误的根源都是没按文件类型做分层缓存。HTML 需要短缓存或不缓存(确保用户拿到最新页面),静态资源(JS/CSS)可以长缓存(配合文件 hash 做版本化),API 的缓存策略取决于数据特性。

    flowchart TD
    A[浏览器请求] –> B{资源类型}

    B –>|HTML 页面| C[Cache-Control: no-cache<br/>或 max-age=0, must-revalidate]
    B –>|静态资源 JS/CSS| D[Cache-Control: max-age=31536000, immutable]
    B –>|API 响应| E{数据类型}

    C –> F[CDN 缓存: 不做或短缓存]

    D –> G{文件名含 hash?}
    G –>|是| H[CDN 缓存: 永久]
    G –>|否| I[CDN 缓存: 短缓存 + 版本参数]

    E –>|实时数据| J[Cache-Control: no-store]
    E –>|半实时| K[Cache-Control: max-age=60, stale-while-revalidate=300]
    E –>|静态数据| L[Cache-Control: max-age=3600]

    二、分层的核心原则

    第一层:HTML 入口文件

    Cache-Control: public, max-age=0, must-revalidate
    CDN: 不做缓存

    这是最关键的一层。HTML 引用了所有 JS/CSS,如果 HTML 被缓存了,用户拿到的是旧版 HTML,它引用的是旧版 JS/CSS——整条缓存链全废了。

    max-age=0, must-revalidate 不是不缓存,是每次请求都要验证(conditional request)。CDN 回源验证,如果 304 Not Modified,CDN 返回缓存的副本。这个开销比完全重新下载小得多。

    第二层:静态资源(JS/CSS/Font/Image)

    Cache-Control: public, max-age=31536000, immutable
    CDN: 长缓存,配合文件 hash

    文件名带 content hash(如 main.a3f2b1c.js),资源永久不可变。immutable 告诉浏览器:即使强制刷新也不要重新验证——因为内容永远不会变。这是 Webpack/Vite 的默认策略。

    第三层:API 响应

    API 的缓存最复杂,需要根据数据特性细分:

    • 实时数据:Cache-Control: no-store(不缓存,每次请求源站)
    • 半实时数据:Cache-Control: max-age=60, stale-while-revalidate=300(缓存 60 秒,过期后允许返回过期数据 300 秒的同时后台异步刷新)
    • 准静态数据:Cache-Control: max-age=3600, stale-while-revalidate=86400

    三、Nginx + CDN 分层配置

    # nginx.conf —— 按文件路径分层缓存

    # ==== 第一层:HTML 入口文件 ====
    # 指定 HTML 类型的请求不做 CDN 长缓存
    location / {
    # 对于 SPA 的入口 HTML
    if ($request_uri ~* "\\.html$") {
    add_header Cache-Control "public, max-age=0, must-revalidate" always;
    # X-Cache-Bypass 告诉 CDN 每次都回源验证
    add_header X-Cache-Bypass "1" always;
    }

    # try_files 优先找精确文件,找不到 fallback 到 index.html(SPA 路由)
    try_files $uri $uri/ /index.html;
    }

    # ==== 第二层:静态资源(带 hash 的文件名) ====
    location /assets/ {
    # 静态资源目录,所有文件带 hash
    expires 1y;
    add_header Cache-Control "public, max-age=31536000, immutable" always;

    # 关键安全头:禁止 MIME 嗅探
    add_header X-Content-Type-Options "nosniff" always;

    # 为不同类型设置正确的 Content-Type
    types {
    application/javascript js mjs;
    text/css css;
    image/svg+xml svg;
    font/woff2 woff2;
    }

    # gzip 预压缩——CDN 可以直接返回预压缩文件
    gzip_static on;
    gzip_vary on;
    }

    # ==== 第三层:API 代理 ====
    location /api/ {
    proxy_pass http://backend-service;

    # 基础代理设置
    proxy_http_version 1.1;
    proxy_set_header Connection "";

    # 根据 URL 前缀设置不同的缓存策略
    # 分类依据:数据的变化频率

    # 实时数据(不缓存)
    location /api/realtime/ {
    proxy_pass http://backend-service;
    add_header Cache-Control "no-store" always;
    }

    # 半实时数据(短缓存 + stale-while-revalidate)
    location /api/dashboard/ {
    proxy_pass http://backend-service;
    add_header Cache-Control "public, max-age=60, stale-while-revalidate=300" always;
    }

    # 准静态数据(长缓存)
    location /api/config/ {
    proxy_pass http://backend-service;
    add_header Cache-Control "public, max-age=3600, stale-while-revalidate=86400" always;
    }
    }

    四、缓存更新与失效策略

    静态资源的缓存更新

    文件 hash 是核心武器。部署流程:

  • 构建时生成带 hash 的文件名(main.a3f2b1c.js)
  • HTML 更新引用新的 hash 文件名
  • 部署到 CDN——新文件有新的 URL,旧文件保留(不影响旧 HTML 的用户)
  • 用户下次请求 HTML 时获取新引用
  • 这就是为什么 HTML 不能用长缓存——它是"切换开关"。

    CDN 主动刷新

    # 批量刷新目录下的所有文件
    curl -X POST "https://cdn-provider/api/purge" \\
    -H "Authorization: Bearer $CDN_TOKEN" \\
    -d '{"paths": ["/assets/*"]}'

    注意:干完活要等 CDN 节点生效——全球 CDN 刷新通常需要 1-5 分钟。

    不建议的做法

    • 给静态资源加版本查询参数(main.js?v=1.2.3):很多 CDN 默认忽略 query string,缓存不生效
    • HTML 也做长缓存:一旦缓存,用户永远看不到新版本
    • 没有 stale-while-revalidate 的长缓存:缓存过期瞬间所有请求打回源站

    五、总结

    前端缓存的分层设计核心就一句话:HTML 是开关,静态资源是货物,API 是水龙头。开关要灵敏(短缓存/不缓存),货物可以囤(长缓存 + hash),水龙头按需开(数据特性决定缓存策略)。三层各自独立配置后,缓存命中率可以从 40% 提升到 90%,源站压力下降 2/3。

    赞(0)
    未经允许不得转载:171主机测评 » 前端 CDN 缓存策略调优:静态资源、HTML 与 API 分层设计
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址