在 nginx 中,`proxy_cache_bypass` 配合 `proxy_pass` 使用时,核心逻辑是:当请求命中缓存时,nginx 会先检查 `proxy_cache_bypass` 定义的键值(如 cookie、header 或变量),如果这些键值的计算结果为非零或非空字符串,则跳过从缓存读取的步骤,直接向后端服务器发起新的代理请求。这意味着即使开启了缓存,只要满足特定条件(例如用户登录状态变化或携带特定 token),nginx 就会绕过缓存层,直接获取最新内容并返回给客户端。

如何配置 proxy_cache_bypass 以忽略特定 Header
要实现基于 HTTP 请求头的缓存绕过,需要在 `http` 或 `server` 块中定义一个变量来存储该 Header 的值,然后在 `location` 块中将此变量赋值给 `proxy_cache_bypass`。这样,当请求中包含特定的 Header 且其值为非空时,Nginx 将不会尝试从磁盘或内存缓存中查找响应,而是直接通过 `proxy_pass` 转发到后端。

server {
listen 80;
server_name example.com;
# 定义缓存路径和级别
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=my_cache:10m max_size=1g inactive=60m;
location /api/data {
# 设置后端代理地址
proxy_pass http://backend_server;
# 启用缓存
proxy_cache my_cache;
# 定义缓存密钥,基于 URI 和 Host
proxy_cache_key $scheme$request_method$host$request_uri;
# 关键配置:如果 header 'X-Cache-Bypass' 存在且不为空,则 bypass 缓存
set $bypass_header $http_x_cache_bypass;
proxy_cache_bypass $bypass_header;
# 确保后端知道这是缓存绕过请求(可选,用于调试)
add_header X-Cache-Status $upstream_cache_status;
}
}
在上述配置中,`set $bypass_header $http_x_cache_bypass;` 这一行提取了名为 `X-Cache-Bypass` 的请求头。如果客户端发送请求时携带 `X-Cache-Bypass: true`,`$bypass_header` 变量的值将为 "true"(非空)。此时 `proxy_cache_bypass` 的条件成立,Nginx 不会查询 `my_cache` 中的缓存数据,而是直接通过 `proxy_pass` 将请求发送给 `backend_server`。如果未携带该 Header 或值为空,`$bypass_header` 为空,Nginx 则会正常执行缓存查找流程。这种机制常用于调试接口或强制刷新特定资源,而无需修改全局缓存策略。
如何结合 Cookie 实现动态内容绕过
除了 Header,更常见的场景是基于 Cookie 的缓存绕过,特别是针对用户个性化内容。通过检查特定的 Cookie 是否存在或具有特定值,可以决定是否为当前用户生成新的缓存版本或直接使用后端响应。这在处理包含敏感信息或实时数据的页面时非常有用。

server {
listen 80;
server_name example.com;
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=user_cache:10m max_size=1g inactive=60m;
location /user/profile {
proxy_pass http://backend_server;
proxy_cache user_cache;
proxy_cache_key $uri$is_args$args;
# 检查是否有 'nocache' cookie,如果有且值不为 'false',则 bypass
set $bypass_cookie 0;
if ($http_cookie ~* "nocache=(.+)") {
set $bypass_cookie $1;
}
# 如果 bypass_cookie 不为 0 且不为空,则 bypass
proxy_cache_bypass $bypass_cookie;
# 同时设置 cache_control 以确保浏览器也不缓存
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header X-Cache-Status $upstream_cache_status;
}
}
在这个例子中,我们使用了 `if` 指令来解析 `Cookie` 头中的 `nocache` 字段。正则表达式 `~* "nocache=(.+)"` 捕获了 `nocache=` 后面的值。如果请求中不包含 `nocache` Cookie,`$bypass_cookie` 保持为初始值 `0`,`proxy_cache_bypass` 条件不满足,Nginx 正常走缓存流程。如果请求中包含 `nocache=1`,`$bypass_cookie` 变为 `1`,`proxy_cache_bypass` 条件满足,Nginx 绕过缓存,直接从后端获取最新的用户配置文件。这种方法允许前端通过设置特定的 Cookie 来控制缓存行为,适用于需要精细控制缓存粒度的应用场景。注意,`proxy_cache_bypass` 仅影响是否从缓存读取,不影响是否向缓存写入,如果需要同时禁止写入,还需配合 `proxy_no_cache` 使用。
当 proxy_cache_bypass 与 proxy_no_cache 同时生效时的具体结果是什么
当 `proxy_cache_bypass` 和 `proxy_no_cache` 同时被配置且条件均满足时,Nginx 的具体行为是:既不从缓存中读取响应,也不将后端的响应写入缓存。也就是说,请求完全穿透缓存层,形成一次纯粹的代理请求。这对于需要完全动态、永不落盘的内容至关重要。
考虑以下代码片段:
location /dynamic/ {
proxy_pass http://backend_server;
proxy_cache my_cache;
proxy_cache_key $request_uri;
# 条件 A: 如果 Header 'Bypass' 存在,则 bypass 读取
proxy_cache_bypass $http_bypass;
# 条件 B: 如果 Header 'NoStore' 存在,则 no_store 写入
proxy_no_cache $http_nostore;
}
假设客户端发送请求,同时携带 `Bypass: yes` 和 `NoStore: yes` 两个 Header。首先,Nginx 检查 `proxy_cache_bypass`,由于 `$http_bypass` 为非空,条件成立,Nginx 决定不查询 `my_cache` 目录下的缓存文件。接着,Nginx 向后端发起请求并获得响应。在决定是否保存该响应时,Nginx 检查 `proxy_no_cache`,由于 `$http_nostore` 也为非空,条件同样成立,Nginx 决定不将该响应保存到磁盘。最终结果是:用户获得了最新的后端数据,但该数据没有被缓存下来,下一次相同请求若不带这两个 Header,仍可能命中旧缓存(如果之前有缓存的话)或重新生成新缓存。这种组合确保了特定请求的“只读不写”特性,常用于日志收集、实时监控面板等场景,避免缓存污染或磁盘空间浪费。











