Nginx的缓存配置--客户端缓存 (Browser Caching)和代理服务器缓存 (Proxy Server Caching)

张开发
2026/4/10 22:30:37 15 分钟阅读
Nginx的缓存配置--客户端缓存 (Browser Caching)和代理服务器缓存 (Proxy Server Caching)
Nginx 的缓存配置主要分为两个层面它们协同工作以最大化网站性能和减轻后端负载客户端缓存 (Browser Caching):通过设置 HTTP 响应头指示用户的浏览器缓存静态资源如图片、CSS、JS。代理服务器缓存 (Proxy Server Caching):Nginx 作为反向代理缓存后端应用服务器如 Node.js, Java, Python 应用的动态响应后续相同请求可直接由 Nginx 返回无需访问后端。 客户端缓存配置 (控制浏览器)客户端缓存的核心是通过 Nginx 向浏览器发送特定的 HTTP 响应头告知浏览器如何以及多久缓存资源。主要涉及Cache-Control和Expires头。在 Nginx 中我们通常使用add_header指令来精确控制这些头信息或者使用expires指令进行快捷设置。1. 静态资源长期缓存对于不常变动的静态资源如图片、字体、CSS/JS 文件可以设置较长的缓存时间。特别是对于通过构建工具如 Webpack, Vite生成的、文件名中包含内容哈希如main.a1b2c3d4.js的资源可以设置非常激进的缓存策略。server { listen 80; server_name example.com; root /var/www/html; # 场景1: 带哈希的静态资源 (推荐) # 缓存1年并标记为 immutable (不可变)浏览器在有效期内不会发起任何验证请求 location ~* \.[a-f0-9]{8,}\.(css|js|png|jpg|jpeg|svg|webp|ico|woff|woff2)$ { add_header Cache-Control public, max-age31536000, immutable always; access_log off; # 可选关闭日志以减少IO } # 场景2: 普通静态资源 # 缓存30天允许浏览器和CDN缓存 location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|ico|woff|woff2)$ { add_header Cache-Control public, max-age2592000 always; access_log off; } }2. HTML 文件缓存策略HTML 文件尤其是单页应用的入口index.html是应用的骨架会频繁更新。因此不应对其进行长期缓存但可以避免每次都完全重新下载。server { # ... 其他配置 # 场景3: HTML 文件 # private: 只允许用户浏览器缓存不允许CDN等中间代理缓存 # no-cache: 使用前必须向服务器验证资源是否更新 # must-revalidate: 缓存过期后必须成功向源服务器验证后才能使用 location ~* \.html$ { add_header Cache-Control private, no-cache, must-revalidate always; } }注意: 此策略依赖于 Nginx 自动提供的ETag或Last-Modified响应头浏览器会使用它们发起条件请求如If-None-Match服务器若判断未更新则返回304 Not Modified从而节省带宽。3. 禁用动态内容缓存对于包含用户敏感信息或实时变化的动态内容如API接口、用户个人资料页必须禁用缓存以防止信息泄露和数据不一致。server { # ... 其他配置 # 场景4: 动态内容/API # no-store: 最严格的指令指示浏览器和所有中间代理不得缓存任何内容 location /api/ { add_header Cache-Control no-store always; # ... 代理到后端应用的配置 } }强制缓存和协商缓存强制缓存是“直接用本地缓存不找服务器”协商缓存是“先问服务器缓存还能不能用能用就用不能用再下载”。1. 强制缓存强制缓存是性能最优的策略。一旦配置生效浏览器在有效期内直接使用本地缓存完全不与服务器进行任何网络交互。核心机制响应头由Cache-Control和Expires控制。状态码命中时浏览器控制台显示200 (from disk cache)或200 (from memory cache)。优先级Cache-Control的优先级高于Expires如果同时存在。Nginx 配置示例通常用于图片、CSS、JS 等不常变动的静态资源。location ~* \.(jpg|jpeg|png|gif|css|js|woff2|woff)$ { # 1. 设置缓存有效期为 1 年 (31536000 秒) # 2. public: 允许所有用户包括 CDN缓存 # 3. immutable: 告诉浏览器文件在有效期内不会变刷新也不会检查更新极致优化 add_header Cache-Control public, max-age31536000, immutable always; # 或者使用 expires 指令效果等同于设置 max-age 和 Expires # expires 1y; }常见指令详解指令值含义max-age3600缓存有效时间为 3600 秒。public允许浏览器和中间代理如 CDN缓存。private只允许浏览器缓存不允许 CDN 缓存。no-cache跳过强制缓存直接进入协商缓存阶段每次都要问服务器。no-store禁止一切缓存每次都从服务器下载用于敏感数据。2. 协商缓存当强制缓存过期或设置为no-cache时浏览器会向服务器发起请求询问资源是否更新。这就是协商缓存。核心机制响应头由Last-Modified/ETag控制。请求头浏览器会带上If-Modified-Since或If-None-Match进行验证。状态码未修改返回304 Not Modified浏览器继续使用本地缓存。已修改返回200 OK和新资源。两种对比策略策略依据缺点优先级基于时间Last-Modified(服务端)If-Modified-Since(客户端)精度只有秒级如果文件修改时间变了但内容没变也会重新下载。较低基于哈希ETag(服务端)If-None-Match(客户端)消耗服务器性能需计算文件哈希。较高注意如果同时存在ETag和Last-Modified服务器会优先根据ETag进行判断。Nginx 配置示例Nginx 默认会自动根据文件属性生成ETag和Last-Modified通常无需显式配置但你可以手动开启或调整。location / { # 强制缓存失效每次都协商 add_header Cache-Control no-cache, must-revalidate always; # 开启 ETag (默认开启) etag on; # 开启 Last-Modified (默认开启) # last_modified on; }两种缓存的配合流程在实际应用中这两种缓存通常是配合工作的。流程如下首次访问浏览器请求资源Nginx 返回200 资源内容 Cache-Control: max-age60ETag。60秒内再次访问命中强制缓存直接读取本地不请求服务器。60秒后再次访问强制缓存过期。浏览器发起请求带上If-None-Match: [ETag值]。服务器判断若文件未变返回304空内容。浏览器更新缓存有效期继续使用旧文件。若文件已变返回200 新文件 新ETag。Nginx 最佳实践配置针对不同类型资源采用不同的缓存策略server { listen 80; server_name example.com; # --- 策略 1: 静态资源 (带哈希指纹的文件) --- # 适用于 main.a1b2.js 这种文件名带哈希的资源 # 策略强缓存 1 年永不协商 location ~* \.[a-f0-9]{8,}\.(js|css|png|jpg)$ { add_header Cache-Control public, max-age31536000, immutable always; access_log off; } # --- 策略 2: 普通静态资源 --- # 适用于 logo.png 这种文件名不变的资源 # 策略强缓存 30 天 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { add_header Cache-Control public, max-age2592000 always; } # --- 策略 3: HTML 文件 --- # 适用于 index.html # 策略不做强缓存每次必须协商 (no-cache) # 确保用户能第一时间获取最新的 JS/CSS 入口 location ~* \.html$ { add_header Cache-Control private, no-cache, must-revalidate always; } # --- 策略 4: 动态 API 接口 --- # 策略禁止缓存 location /api/ { add_header Cache-Control no-store always; proxy_pass http://backend; } }强制缓存 (Cache-Control: max-age)性能最高用于静态文件。协商缓存 (ETag/Last-Modified)用于验证文件是否更新用于 HTML 或频繁变动的资源。组合拳HTML 使用no-cache协商缓存引用的 JS/CSS 使用max-age31536000强缓存并配合文件名哈希是前端工程化的标准做法。 代理服务器缓存配置 (缓存后端响应)代理缓存将后端应用的响应通常是动态生成的保存在 Nginx 服务器的磁盘上。当收到相同请求时Nginx 可以直接从磁盘读取并返回极大地减轻了后端负载提升了响应速度。配置代理缓存分为两步定义缓存区和在location中启用。1. 定义缓存区 (http块)在nginx.conf的http上下文中使用proxy_cache_path指令定义缓存的存储路径、内存索引区和清理策略。http { # ... 其他 http 配置 # 定义一个名为 my_cache 的缓存区 proxy_cache_path /var/cache/nginx levels1:2 keys_zonemy_cache:10m max_size1g inactive60m use_temp_pathoff; server { # ... 服务器配置 } }参数详解/var/cache/nginx: 缓存文件在磁盘上的存储路径。levels1:2: 设置缓存目录的层级结构避免单个目录下文件过多影响性能。keys_zonemy_cache:10m: 定义一个名为my_cache的共享内存区10MB用于存储缓存键和元数据如访问次数、过期时间。10MB 大约能存储 80,000 个键。max_size1g: 磁盘上缓存文件的最大总容量。超出后Nginx 会根据 LRU最近最少使用算法清理。inactive60m: 如果缓存项在 60 分钟内未被访问即使未过期也会被清理。use_temp_pathoff: 建议关闭让 Nginx 直接将临时文件写入缓存目录避免不必要的文件拷贝提升性能。2. 在location中启用缓存在需要缓存的location块中使用proxy_cache等指令启用并细化缓存行为。server { listen 80; server_name api.example.com; location / { # 启用缓存使用上面定义的 my_cache 缓存区 proxy_cache my_cache; # 定义缓存键确保唯一性 # 这里将协议、主机、URI和查询参数组合作为键 proxy_cache_key $scheme$host$request_uri; # 针对不同后端响应状态码设置缓存时间 proxy_cache_valid 200 302 10m; # 成功响应缓存10分钟 proxy_cache_valid 404 1m; # 404响应缓存1分钟避免缓存无效请求过久 # 添加响应头便于调试缓存命中状态 (HIT/MISS) add_header X-Cache-Status $upstream_cache_status; # 高级配置防止缓存雪崩 # 当缓存过期时只允许一个请求回源更新其他请求等待 proxy_cache_lock on; # 在后台异步更新过期缓存同时先给用户返回旧缓存 proxy_cache_background_update on; # 在后端出错或超时时允许返回过期缓存 proxy_cache_use_stale error timeout http_500 http_502 http_503 http_504; # 代理到后端服务器 proxy_pass http://backend_server; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }关键指令说明proxy_cache: 指定使用的缓存区名称。proxy_cache_key: 定义缓存的唯一标识。合理的键设计可以避免缓存碎片化。proxy_cache_valid: 定义不同响应码的缓存时长。X-Cache-Status: 通过添加此响应头你可以用curl -I命令检查请求是命中缓存 (HIT) 还是未命中 (MISS)。proxy_cache_lock: 防止“缓存雪崩”即大量请求同时发现缓存过期并涌向后端。proxy_cache_background_update: 提升用户体验用户能立即获得响应即使是旧的同时 Nginx 在后台无感更新缓存。通过合理配置客户端缓存和代理服务器缓存可以构建一个高效、高性能的 Web 服务架构。

更多文章