为什么要配置缓存策略

SPA 应用(Vue/React/uni-app H5)打包后,静态资源(JS/CSS/图片)的文件名通常包含内容 hash(如 index-a3f2b1.js)。合理配置缓存策略可以带来以下收益:

配置缓存的优势

优势 说明
提升页面加载速度 带 hash 的 JS/CSS/图片缓存到浏览器,二次访问无需重新下载,加载速度提升 50%-80%
降低服务器带宽 静态资源命中浏览器缓存后不再请求服务器,减少流量消耗
减轻服务器压力 减少静态资源的请求处理量,服务器只需处理动态接口
保证更新及时生效 入口文件 index.html 不缓存,确保用户始终加载最新版本的 JS/CSS 引用
改善移动端体验 移动端网络不稳定、带宽有限,缓存可显著减少加载时间

不配置缓存的缺点

缺点 影响
每次全量下载 用户每次访问都要重新下载全部 JS/CSS/图片,页面加载慢
浪费带宽 一个 SPA 应用打包后通常几百 KB 到几 MB,重复下载浪费流量
移动端体验差 4G/弱网环境下,无缓存的 SPA 首次加载可能需要 5-10 秒
服务器压力大 所有静态资源每次都要从服务器读取和传输
CDN 无法发挥效果 即使使用 CDN,无缓存策略也会导致频繁回源

配置缓存的潜在风险

风险 应对措施
用户看到旧版本 入口文件 index.html 设置不缓存,确保每次获取最新的 JS/CSS 引用
发版后不生效 带 hash 的资源文件名变化后自动走新文件,旧缓存不影响更新
配置复杂度高 使用 map 集中配置方案,降低维护成本
缓存穿透 always 参数确保 4xx/5xx 响应也带缓存头,避免错误页面被反复请求

方案一:map 集中配置(当前采用)

通过 map 指令按 URI 模式匹配,自动决定缓存策略,所有 location 共用一个变量。

# http 块中集中维护
map $uri $cache_control {
    default         "";
    ~*\.html$       "no-cache, no-store, must-revalidate";
    ~/assets/       "public, max-age=31536000, immutable";
}

server {
    # PC端
    location / {
        try_files $uri $uri/ /index.html;
        add_header Cache-Control $cache_control always;
    }

    # 移动端
    location /mobile {
        alias /opt/project/application/front-h5;
        index index.html;
        try_files $uri $uri/ /mobile/index.html;
        add_header Cache-Control $cache_control always;
    }
}

方案二:传统分散配置

在每个 location 中单独写 add_header,需要为不同缓存策略拆分多个 location。

server {
    # PC端
    location / {
        try_files $uri $uri/ /index.html;
    }

    location = /index.html {
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";
    }

    location /assets/ {
        add_header Cache-Control "public, max-age=31536000, immutable";
    }

    # 移动端
    location /mobile {
        alias /opt/project/application/front-h5;
        index index.html;
        try_files $uri $uri/ /mobile/index.html;
    }

    location = /mobile/index.html {
        alias /opt/project/application/front-h5/index.html;
        add_header Cache-Control "no-cache, no-store, must-revalidate";
        add_header Pragma "no-cache";
        add_header Expires "0";
    }

    location /mobile/assets/ {
        alias /opt/project/application/front-h5/assets/;
        add_header Cache-Control "public, max-age=31536000, immutable";
    }
}

方案三:传统简单配置(直接在主 location 加 header)

不拆分子 location,直接在主 location 中添加缓存头,所有文件统一处理。

server {
    # PC端
    location / {
        try_files $uri $uri/ /index.html;
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }

    # 移动端
    location /mobile {
        alias /opt/project/application/front-h5;
        index index.html;
        try_files $uri $uri/ /mobile/index.html;
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }
}

优缺点对比

对比维度 map 集中配置 传统分散配置 传统简单配置
location 数量 2 个 6 个 2 个
缓存规则维护 只改 map 一个地方 需改 4 个 location 改 2 个 location
路径维护 alias 各写 1 次 alias 写 3 次 alias 写 1 次
缓存精度 html 不缓存 + assets 长期缓存 html 不缓存 + assets 长期缓存 全部不缓存
带 hash 资源缓存 1 年(性能最优) 1 年(性能最优) 不缓存(每次重新下载)
页面加载速度 慢(JS/CSS/图片每次全量下载)
流量消耗
alias 继承问题 有(易出 404)
兼容性 nginx 1.7.5+ 所有版本 所有版本
可读性 规则集中,一目了然 分散各处 简单直接
新增缓存规则 map 加一行 新增 location 块 不好加,只能全部统一
适用规模 中大型项目 中大型项目 小型/临时项目

方案三的典型问题

这种方案最大的问题是所有静态资源都不缓存

  • 用户每次打开页面,浏览器都要重新下载全部 JS、CSS、图片、字体
  • 一个 uni-app H5 应用打包后通常有 50-100 个静态文件,总计几百 KB 到几 MB
  • 在移动网络(4G/弱网)环境下,用户体验会明显变差
  • 服务器带宽浪费严重

唯一的优点是配置最简单,且不会出 alias 继承导致的 404 问题。

适用场景

推荐用 map 集中配置(方案一)

  • SPA 项目(Vue/React/uni-app H5),缓存规则统一
  • 多个入口(PC + 移动端)共用同一套缓存策略
  • 团队多人维护,降低改错风险
  • nginx 版本 ≥ 1.7.5

推荐用传统分散配置(方案二)

  • 需要对某个特定路径做完全不同的缓存策略
  • nginx 版本较老(< 1.7.5)
  • 需要同时设置 PragmaExpires 等额外 header 兼容旧浏览器

可用传统简单配置(方案三)

  • 小型或临时项目,不在意性能
  • 对 nginx 配置不熟悉,不想踩 alias 继承的坑
  • 静态资源很小(只有几个文件),缓存收益不明显
  • 内部测试环境,不面向用户

注意事项

map 方案的注意点

  1. add_header 使用变量时,若变量为空字符串 "",nginx 不会发送该 header(符合预期)
  2. always 参数确保即使响应码为 4xx/5xx 也会带上 header
  3. map 中的正则匹配按从上到下的顺序,首个匹配生效

传统方案的常见坑

  1. alias 不继承(方案二):子 location(如 location = /mobile/index.html)不会继承父 location 的 alias,会回退到 server 级 root,导致 404
  2. add_header 覆盖问题(方案二):子 location 中的 add_header 会覆盖父 location 的所有 add_header,不是追加
  3. 维护遗漏(方案二):新增前端入口时容易忘记同步缓存配置
  4. 全量下载浪费带宽(方案三):所有静态资源每次访问都重新下载,移动端用户体感明显

总结

方案一 (map) 方案二 (分散) 方案三 (简单)
配置复杂度
缓存精度
性能表现
维护成本
出错风险
综合评价 推荐 特殊场景 临时使用
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐