应提取关键参数构造稳定缓存键:在http块中用map提取id、lang等核心参数,proxy_cache_key仅组合可信变量;对大小写、空格等做归一化;含ts、random等动态参数的请求直接绕过缓存;通过x-cache-key响应头和日志验证key一致性。

直接用 $request_uri 作缓存键,会让 ?utm_source=weibo&id=123 和 ?id=123&utm_source=wechat 被当成两个不同资源——其实它们语义一致,只是多了干扰参数。关键不是“去掉哪些”,而是“只保留哪些”。
提取关键参数构造稳定 key
不依赖完整查询串,而是用 map 提前提取真正影响内容的参数(如 id、lang、version),其余一律丢弃。Nginx 不解析 query string,但可以通过变量拼接生成标准化键。
- 在
http块中定义 map,把关键参数转为独立变量:
map $args $cache_id {<br> ~*id=([^&]+) $1;<br> default "";<br>}<br>map $args $cache_lang {<br> ~*lang=([^&]+) $1;<br> default "zh";<br>}
- 然后在
proxy_cache_key中只组合这些可信变量:proxy_cache_key "$scheme$request_method$host$uri$is_args$id=$cache_id&lang=$cache_lang";
统一格式,避免大小写与空格干扰
参数值含大小写或 URL 编码差异(如 LANG=EN vs lang=en)也会导致 key 不一致。可在 map 中做归一化处理:
- 用正则捕获后转小写(需配合
perl_set或 Lua 模块); - 更轻量的做法是:约定后端统一接收小写参数,并在 Nginx 层用
rewrite强制重写,再进入缓存逻辑; - 对空格、多余空格、重复参数等,靠提前清理
$args更可靠——比如用set $args覆盖为精简后的字符串。
跳过含敏感或动态参数的请求
有些参数本身就不该进缓存,比如 ts=123456789(时间戳)、random=xxx、debug=true。与其在 key 里过滤,不如让这类请求根本绕过缓存:
- 用
proxy_cache_bypass和proxy_no_cache配合判断:
proxy_cache_bypass $arg_ts $arg_random $arg_debug;<br>proxy_no_cache $arg_ts $arg_random $arg_debug;
- 这样带这些参数的请求不会读缓存、也不会写缓存,彻底规避污染。
验证 key 是否真的一致
光配对没用,得看到效果。加个响应头看实际生成的 key:
-
add_header X-Cache-Key $cache_key;(需先用set $cache_key "...";构造) - 搭配
add_header X-Cache-Status $upstream_cache_status;对比命中情况 - 查 Nginx 日志时,把
$cache_key加入 log_format,方便统计 key 分布和重复率











