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

Nginx 的缓存配置主要分为两个层面,它们协同工作以最大化网站性能和减轻后端负载:

  1. 客户端缓存 (Browser Caching): 通过设置 HTTP 响应头,指示用户的浏览器缓存静态资源(如图片、CSS、JS)。
  2. 代理服务器缓存 (Proxy Server Caching): Nginx 作为反向代理,缓存后端应用服务器(如 Node.js, Java, Python 应用)的动态响应,后续相同请求可直接由 Nginx 返回,无需访问后端。

🌐 客户端缓存配置 (控制浏览器)

客户端缓存的核心是通过 Nginx 向浏览器发送特定的 HTTP 响应头,告知浏览器如何以及多久缓存资源。主要涉及 Cache-ControlExpires 头。

在 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-age=31536000, 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-age=2592000" 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 自动提供的 ETagLast-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-ControlExpires 控制。
  • 状态码: 命中时,浏览器控制台显示 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-age=31536000, immutable" always;
    
    # 或者使用 expires 指令(效果等同于设置 max-age 和 Expires)
    # expires 1y;
}
常见指令详解
指令值 含义
max-age=3600 缓存有效时间为 3600 秒。
public 允许浏览器和中间代理(如 CDN)缓存。
private 只允许浏览器缓存,不允许 CDN 缓存。
no-cache 跳过强制缓存,直接进入协商缓存阶段(每次都要问服务器)。
no-store 禁止一切缓存,每次都从服务器下载(用于敏感数据)。

  1. 协商缓存

当强制缓存过期(或设置为 no-cache)时,浏览器会向服务器发起请求,询问资源是否更新。这就是协商缓存。

核心机制
  • 响应头:Last-Modified / ETag 控制。
  • 请求头: 浏览器会带上 If-Modified-SinceIf-None-Match 进行验证。
  • 状态码:
    • 未修改: 返回 304 Not Modified,浏览器继续使用本地缓存。
    • 已修改: 返回 200 OK 和新资源。
两种对比策略
策略 依据 缺点 优先级
基于时间 Last-Modified (服务端) If-Modified-Since (客户端) 精度只有秒级;如果文件修改时间变了但内容没变,也会重新下载。 较低
基于哈希 ETag (服务端) If-None-Match (客户端) 消耗服务器性能(需计算文件哈希)。 较高

注意: 如果同时存在 ETagLast-Modified,服务器会优先根据 ETag 进行判断。

Nginx 配置示例

Nginx 默认会自动根据文件属性生成 ETagLast-Modified,通常无需显式配置,但你可以手动开启或调整。

复制代码
location / {
    # 强制缓存失效,每次都协商
    add_header Cache-Control "no-cache, must-revalidate" always;
    
    # 开启 ETag (默认开启)
    etag on;
    
    # 开启 Last-Modified (默认开启)
    # last_modified on; 
}

两种缓存的配合流程

在实际应用中,这两种缓存通常是配合工作的。流程如下:

  1. 首次访问: 浏览器请求资源,Nginx 返回 200 + 资源内容 + Cache-Control: max-age=60 + ETag
  2. 60秒内再次访问: 命中强制缓存,直接读取本地,不请求服务器。
  3. 60秒后再次访问: 强制缓存过期。浏览器发起请求,带上 If-None-Match: [ETag值]
  4. 服务器判断:
    • 若文件未变:返回 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-age=31536000, immutable" always;
        access_log off;
    }

    # --- 策略 2: 普通静态资源 ---
    # 适用于 logo.png 这种文件名不变的资源
    # 策略:强缓存 30 天
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        add_header Cache-Control "public, max-age=2592000" 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-age=31536000(强缓存)并配合文件名哈希,是前端工程化的标准做法。

🔄 代理服务器缓存配置 (缓存后端响应)

代理缓存将后端应用的响应(通常是动态生成的)保存在 Nginx 服务器的磁盘上。当收到相同请求时,Nginx 可以直接从磁盘读取并返回,极大地减轻了后端负载,提升了响应速度。

配置代理缓存分为两步:定义缓存区和在 location 中启用。

1. 定义缓存区 (http 块)

nginx.confhttp 上下文中,使用 proxy_cache_path 指令定义缓存的存储路径、内存索引区和清理策略。

复制代码
http {
    # ... 其他 http 配置

    # 定义一个名为 "my_cache" 的缓存区
    proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m use_temp_path=off;

    server {
        # ... 服务器配置
    }
}

参数详解:

  • /var/cache/nginx: 缓存文件在磁盘上的存储路径。
  • levels=1:2: 设置缓存目录的层级结构,避免单个目录下文件过多影响性能。
  • keys_zone=my_cache:10m: 定义一个名为 my_cache 的共享内存区(10MB),用于存储缓存键和元数据(如访问次数、过期时间)。10MB 大约能存储 80,000 个键。
  • max_size=1g: 磁盘上缓存文件的最大总容量。超出后,Nginx 会根据 LRU(最近最少使用)算法清理。
  • inactive=60m: 如果缓存项在 60 分钟内未被访问,即使未过期也会被清理。
  • use_temp_path=off: 建议关闭,让 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 服务架构。

相关推荐
萝卜白菜。3 小时前
TongWeb8.0 JNDI缓存
开发语言·python·缓存
惺忪97983 小时前
Redis安装与启动
数据库·redis·缓存
橘子编程3 小时前
计算机内存与缓存完全指南
java·计算机网络·spring·缓存
MonkeyKing_sunyuhua3 小时前
Nginx + Let’s Encrypt 免费 SSL 证书 的完整配置过程
运维·nginx·ssl
Renhao-Wan4 小时前
Java 中 Integer 对象的缓存机制与包装类特性
java·缓存
sibylyue4 小时前
Nginx\Tomcat\Jetty\Netty
java·nginx·http
cyber_两只龙宝6 小时前
【Nginx】Nginx反向代理之实现http的反向代理
linux·运维·nginx·http·云原生·反向代理
難釋懷6 小时前
Nginx本地缓存API
nginx·spring·缓存
0xDevNull6 小时前
Redis Lua 脚本详细教程
redis·缓存·lua