前端静态资源缓存与部署实践总结

1. 背景

在与运维沟通时,我们发现前端部署方式的不同,会带来缓存与版本更新上的差异。以前我们通过 bucket 静态托管 ,现在改成了 k8s Pod + Nginx,这中间存在一些需要特别注意的问题。


2. Bucket 部署 vs k8s 部署

  • Bucket 静态托管(增量更新)

    • 构建产物上传到对象存储(S3/OSS/GCS)。
    • 采用增量更新:只上传新生成的 hash 文件,旧文件保留。
    • 用户旧缓存对应的文件依然存在,不会 404。
    • 上线体验平滑。
  • k8s 部署(镜像全量更新)

    • 前端文件打包到镜像中,Pod 滚动更新时全量替换。
    • 旧 Pod 被销毁,旧版本文件随之消失。
    • 在 Pod 切换过程中,用户可能请求到旧 Pod 的 index.html → 加载旧的 JS 文件。

3. 为什么客户端会请求到旧 JS 文件?

主要有以下几类原因:

  1. 浏览器缓存

    • 如果文件名没带 hash,浏览器会用缓存的旧 JS。
    • 即使带 hash,如果 index.html 缓存了,仍然会引用旧的 hash 文件。
  2. Nginx Header 设置不完整

    • 默认 add_header 不会在 304 响应时生效,需要加 always
  3. k8s 滚动更新

    • 在新旧 Pod 共存的窗口期,用户可能请求到旧 Pod 的 index.html
  4. CDN/代理缓存

    • 如果前面挂了 CDN,可能拦截并返回旧文件。

4. 最佳缓存策略

核心思路:

  • 入口文件 index.html:禁止缓存
  • 带 hash 的静态资源(JS/CSS/图片等):长缓存

为什么?

  • index.html 体积小,每次都请求不会影响性能,却能保证用户拿到最新版本。
  • 静态资源带 hash,内容唯一 → 可以放心给长缓存,提高加载性能。

5. 改进版 Nginx 配置

nginx 复制代码
server {
  listen 80 default_server;
  root /usr/share/nginx/html;

  # 默认禁止缓存
  add_header Cache-Control "no-cache, no-store, must-revalidate" always;
  add_header Pragma "no-cache" always;
  add_header Expires 0 always;

  # index.html 禁止缓存
  location = /index.html {
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Expires 0 always;
  }
  location = /v2/index.html {
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
    add_header Pragma "no-cache" always;
    add_header Expires 0 always;
  }

  # 带 hash 的静态资源 → 长缓存
  location ~* \.(?:js|css|png|jpg|jpeg|gif|svg|ico|woff2?|ttf|eot)$ {
    add_header Cache-Control "public, max-age=31536000, immutable" always;
    try_files $uri =404;
  }

  # SPA 路由支持
  location / {
    index index.html;
    try_files $uri $uri/ /index.html;
  }
  location /v2 {
    index index.html;
    try_files $uri $uri/ /index.html;
  }

  # 前端版本信息文件
  location /version {
    index wati-fe-version.json;
    alias /usr/share/nginx/html/;
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
  }

  error_page 500 502 503 504 /50x.html;
  location = /50x.html { root /usr/share/nginx/html; }

  error_page 404 403 /40x.html;
  location = /40x.html { root /usr/share/nginx/html; }
}

6. 总结

  • index.html 禁止缓存:保证用户总能获取最新入口文件。
  • 静态资源长缓存:充分利用 hash 文件名,提升性能。
  • 加上 always:避免 304 时丢失缓存控制头。
  • 注意滚动更新窗口期:可能存在新旧 Pod 并行,带来旧资源问题。

这样配置后,前端项目能既保证 快速更新 ,又能 充分利用缓存性能

相关推荐
JeffongTan14 小时前
在LWC中镶嵌VF Page获取用户IP
前端·javascript·salesforce
不cong明的亚子16 小时前
web live多屏互动平台
javascript·经验分享·音视频
陆枫Larry17 小时前
Astro 是什么
前端
是立不是利18 小时前
写给设计师的 CSS 博客美学指南
前端·css
dsyyyyy110118 小时前
JS复习,难点,易错点总结
开发语言·javascript·ecmascript
默_笙19 小时前
🏝 Docker 就是"房地产开发":从施工图纸到小区物业的容器化指南
前端·javascript
计算机魔术师19 小时前
Rohan Paul 谈用时间跨度衡量智能体能力,并引用 OpenAI 自动化研究实习生里程碑
前端
kyriewen19 小时前
我手写了个极简版 React Router——才搞懂 v6 为什么砍了这么多 API
前端·javascript·程序员
a11177619 小时前
Shirone 二次元博客主题 开源
前端·开源
努力努力再努力wz19 小时前
【Redis入门系列】从 KEYS 到 SCAN:渐进式遍历、Cursor 与位反转原理
数据库·redis·缓存