Nginx缓存与浏览器缓存是分层协作关系而非替代:前者在服务端减少后端压力,后者在客户端减少重复请求;二者作用位置、控制方式和失效逻辑不同,需分开配置、协同设计。

nginx 缓存和浏览器缓存不是替代关系,而是分层协作:浏览器缓存减少重复请求,nginx 服务端缓存(如 proxy_cache)减少后端压力。两者目标一致——降载提速,但作用位置、控制方式和失效逻辑完全不同,必须分开配置、协同设计。
明确分工:谁该缓什么
浏览器缓存只管“用户本地是否要发请求”,靠 Cache-Control 和 Expires 响应头驱动;nginx proxy_cache 则是“Nginx 自己要不要查后端”,靠 proxy_cache_path、proxy_cache_key 和 proxy_cache_valid 控制。两者不能混用,也不能互相覆盖。
- 静态资源(.js、.css、图片等)——优先走浏览器缓存,Nginx 只需加响应头,不启用 proxy_cache
- 动态接口(/api/user、/search)——浏览器通常设为 no-cache 或短 max-age,而 Nginx 可用 proxy_cache 缓存成功响应(如 200),但需显式忽略 Set-Cookie 等默认不缓存头
- HTML 入口文件(index.html)——浏览器设为 private, no-cache,确保每次访问都验证;Nginx 一般不对其 proxy_cache,除非配合 ETag 或版本化路径
静态资源:靠哈希+immutable 实现“永久有效”
对带内容哈希的文件(如 main.a1b2c3.js),浏览器缓存策略可激进些,核心是避免“改了文件用户看不到”:
- 用 add_header Cache-Control "public, max-age=31536000, immutable" always; —— immutable 告诉浏览器:只要没过期,连条件请求(If-None-Match)都不用发
- 匹配规则建议用正则:location ~* \.[a-f0-9]{8,}\.(js|css|png|jpg|woff2)$,精准命中构建产物
- 不要对普通 .js/.css 用 immutable,除非你保证文件名随内容变化
动态内容:proxy_cache + 差异化 TTL 是关键
想让 /api/v1/ 缓 5 分钟、/static/ 图片缓 30 天、/healthz 不缓?单靠 location 匹配不够,得用 map 动态赋值:
- 在 http 块定义:map $request_uri $cache_ttl { ~^/api/v1/ "5m"; ~^/static/ "30d"; ~^/healthz "0s"; default "1m"; }
- 在对应 location 中写:proxy_cache_valid 200 $cache_ttl;(注意:仅支持时间变量,不能用于开关)
- 务必检查:proxy_cache_path 的父目录权限(如 /var/cache/nginx 必须属 nginx 用户)、proxy_cache_key 是否含 $args(否则 ?id=1 和 ?id=2 会命中同一缓存)
避免踩坑的硬性约束
很多缓存不生效,不是配置漏了,而是违反了底层规则:
- 后端已返回 Cache-Control: no-cache → Nginx 的 expires 指令会被无视(HTTP 协议规定响应头以 origin 为准)
- Nginx 默认跳过所有带 Set-Cookie 头的响应 → 如需缓存登录态无关的 API,加 proxy_ignore_headers Set-Cookie;
- proxy_cache_valid 只对指定状态码生效 → 若后端返回 304,即使写了 proxy_cache_valid 200 10m,也不会缓存
- 浏览器按 URL 缓存,Nginx proxy_cache 按 key 缓存 → 同一 URL 但不同请求头(如 Accept-Encoding)可能被当成不同资源,需用 $http_accept_encoding 纳入 key


















