用户登录状态下的缓存隔离关键在于将登录态显式纳入cache_key并配合bypass机制:用正则提取session_id或token中的user_id构造$cache_user_id,再拼入proxy_cache_key;同时通过proxy_cache_bypass和proxy_no_cache对已登录用户强制回源,确保敏感响应不落盘。

用户登录状态下的缓存隔离,核心不是“要不要缓存”,而是“谁的缓存不能混在一起”。Nginx 默认用 $scheme$request_method$host$request_uri$is_args$args 作 key,完全不包含用户身份信息——这就导致未登录用户可能意外命中已登录用户的响应(比如首页带昵称的 HTML),造成信息泄露或渲染错乱。必须让登录态成为 cache_key 的显式组成部分。
用 $cookie_xxx 或 $http_authorization 提取可信标识
直接拼接整个 Cookie 不安全也不稳定(长度不定、含敏感字段、易哈希碰撞)。应提取其中明确、稳定、可验证的字段:
- 若后端写入
session_id=abc123,用正则匹配:map $cookie_session_id $cache_user_id { ~^([a-zA-Z0-9]+)$ $1; default ""; } - 若使用 Bearer Token,匹配前缀并截取 user_id(需配合 auth_request 或 Lua):
map $http_authorization $cache_user_id { ~^Bearer\s+([a-zA-Z0-9\-_]+)\.([a-zA-Z0-9\-_]+)\. $1; default ""; } - 多个来源时联合判断:
map "$cookie_session_id:$http_authorization" $cache_user_id { "" ""; default "logged"; }(仅作布尔标记,适合简单场景)
构造带登录态的 cache_key,且兼容游客
key 必须同时满足两个条件:对已登录用户足够唯一;对未登录用户不破坏通用缓存效率。推荐写法:
proxy_cache_key "$scheme$request_method$host$request_uri$is_args$args$cache_user_id";
- 当
$cache_user_id为空(游客),key 等价于原始默认值,不影响静态页、搜索页等通用内容缓存 - 当
$cache_user_id非空(如u789),key 自动变为新维度,确保该用户专属响应只被自己命中 - 避免用
$cookie_xxx原值——它可能含引号、空格或过长字符串,影响 key 稳定性
配合 proxy_cache_bypass + proxy_no_cache 形成闭环
仅改 key 不够。如果已登录用户请求仍被缓存,而游客又恰好命中了那个 key,依然有风险。必须阻断敏感请求进入缓存链路:
- 定义控制变量:
map $cache_user_id $bypass_and_no_cache { "" 0; default 1; } - 在 location 中成对启用:
proxy_cache_bypass $bypass_and_no_cache;
proxy_no_cache $bypass_and_no_cache; - 效果:只要
$cache_user_id非空,该请求就强制回源、响应绝不落盘——此时 cache_key 是否含用户 ID 已不关键,只是兜底保障
验证是否真正隔离
加两行配置快速确认:
- 日志中记录关键维度:
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $upstream_cache_status "$cache_user_id"'; - 响应头暴露状态:
add_header X-Cache-Status "$upstream_cache_status";<br> add_header X-Cache-User "$cache_user_id";
用不同账号(或清 Cookie 后)访问同一 URL,观察日志里 $upstream_cache_status 是否始终为 MISS/BYPASS,且 $cache_user_id 值正确区分——这就说明隔离生效了。











