http缓存与浏览器缓存

9 阅读4分钟

HTTP 缓存是浏览器、代理服务器、CDN 等根据 HTTP 响应头,把资源副本保存下来,后续请求尽量复用,从而减少网络请求、加快加载、降低服务器压力。

一、两类核心缓存

类型判断依据是否发请求到服务器浏览器表现
强缓存Cache-Control: max-age、Expires不发请求200 (from memory/disk cache)
协商缓存ETag / Last-Modified发请求验证未变:304;变了:200

优先级:

  • Cache-Control > Expires
  • ETag > Last-Modified

二、常用响应头

1. 强缓存相关

http

Cache-Control: max-age=31536000, public, immutable
Expires: Wed, 21 Oct 2026 07:28:00 GMT

常见指令:

  • max-age=秒:资源在多少秒内可直接用本地缓存。
  • s-maxage=秒:只对 CDN、代理等共享缓存生效。
  • public:允许浏览器和 CDN 缓存。
  • private:只允许浏览器缓存,不允许 CDN 缓存。
  • no-cache:可以缓存,但每次使用前必须向服务器验证。
  • no-store:完全不缓存。
  • must-revalidate:过期后必须验证,不能用旧缓存。
  • immutable:资源不会变,浏览器在有效期内不要发验证请求。
  • stale-while-revalidate=秒:过期后先用旧缓存,同时后台更新。

注意:no-cache 不是“不缓存”,no-store 才是“不缓存”。

2. 协商缓存相关

http

ETag: "abc123"
Last-Modified: Tue, 20 Oct 2026 10:00:00 GMT

下次请求会带上:

http

If-None-Match: "abc123"
If-Modified-Since: Tue, 20 Oct 2026 10:00:00 GMT

服务器判断:

  • 没变:返回 304 Not Modified,不返回资源体。
  • 变了:返回 200 OK 和新资源。

三、缓存流程

  1. 第一次请求资源,服务器返回 200 和缓存头。
  2. 再次请求时,先看强缓存是否还在有效期内。
  3. 有效:直接使用本地缓存,不发请求。
  4. 失效:带 If-None-Match / If-Modified-Since 请求服务器。
  5. 服务器返回 304:继续用本地缓存,并更新缓存头。
  6. 服务器返回 200:用新资源覆盖缓存。
  7. 如果响应是 no-store,则完全不保存。
  8. 整个流程静态资源放在nginx里设置,一些接口如果是获取地区的接口可以放入后端设置响应头,浏览器下次自动携带
浏览器请求资源
    ↓
是否有本地缓存?
    ├─ 无 → 请求服务器,返回200,同时带回缓存头,存入本地
    └─ 有 → 判断【强缓存是否有效】(max-age/Expires)
            ├─ ✅命中强缓存 → 直接读本地缓存 200(from cache),不访问后端
            └─ ❌强缓存过期 → 发起请求,带上协商缓存标识(If-Modified-Since / If-None-Match)
                    ↓
                服务器对比
                    ├─ ✅内容没变 → 返回304 Not Modified,无响应body,浏览器复用本地缓存
                    └─ ❌内容变更 → 返回200 + 新资源 + 新缓存头,更新本地缓存

四、常见缓存位置

  • 浏览器内存缓存:memory cache,速度快,页面关闭可能消失。
  • 浏览器磁盘缓存:disk cache,持久化。
  • Service Worker Cache:前端可编程控制。
  • CDN / 反向代理缓存:共享缓存,常配合 s-maxage。
  • 代理服务器(Nginx)缓存:企业网关、运营商缓存等。
  • localStorage:用于亮暗模式,用户偏好
  • Cookie:Set-Cookie: session_id=xxx; HttpOnly; Secure; SameSite=Lax; Max-Age=86400
  • indexedDB:大数据,离线邮箱,笔记,新闻,视频
  • Server Worker

五、Nginx缓存

一个典型的前端项目 Nginx 配置片段如下:

server {
    listen 80;
    server_name your-domain.com;

    # 项目根目录(请替换为你的实际路径)
    root /usr/share/nginx/html;

    # 1. 针对带哈希值的静态资源(如 app.abc123.js)配置长期强缓存
    location ~* \.[a-f0-9]{8,}\.(js|css|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
        # 强缓存1年,并标记为不可变,浏览器在有效期内不会发起验证请求
        add_header Cache-Control "public, max-age=31536000, immutable" always;
        access_log off; # 可选:关闭日志以减少磁盘I/O
    }

    # 2. 针对其他固定名称的静态资源(如 logo.png)配置较短的强缓存
    location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ {
        # 强缓存30天,允许浏览器和CDN缓存
        add_header Cache-Control "public, max-age=2592000" always;
    }

    # 3. 针对 HTML 入口文件(如 index.html)配置协商缓存
    location ~* \.html$ {
        # 允许浏览器缓存,但每次使用前必须向服务器验证
        # 'private' 禁止中间代理(如CDN)缓存此响应
        add_header Cache-Control "private, no-cache, must-revalidate" always;
        # Nginx 默认会为此类文件提供 ETag 和 Last-Modified 以支持验证
    }

    # 4. SPA(单页应用)的路由回退配置
    # 这确保了前端路由刷新时不会出现 404 错误
    location / {
        try_files $uri $uri/ /index.html;
    }
}

项目打包好,通过pnpm build 生成dist目录,上传服务器

/usr/share/nginx/html/          # Nginx 配置的 root 目录
├── index.html                  # 应用入口文件
├── assets/                     # 构建工具生成的资源目录
│   ├── app.a1b2c3d4.js         # 带哈希的 JS 文件
│   └── style.e5f6g7h8.css      # 带哈希的 CSS 文件
└── favicon.ico

六、实践建议

  • 带 hash 的静态资源:
    app.8f3a2.js、style.1c9d.css

    http

    Cache-Control: public, max-age=31536000, immutable
    
  • HTML 入口文件:

    http

    Cache-Control: no-cache
    

    这样每次会验证,确保引用最新资源。