不能直接用 $request_body 做缓存键,因其常为空、易被截断或转义、受格式和编码影响导致 key 不一致,且存在敏感信息泄露风险;应改用 get 参数、后端签名透传或结构化字段提取等语义化方案。

直接用 $request_body 做缓存键不可靠,也不推荐——它在多数 Nginx 配置中为空、不可读,且受换行符、空格、编码差异影响,极易导致 key 不一致或命中失败。
为什么不能直接用请求体
原因很实际:
- Nginx 默认不读取或缓存 request body(尤其对非文件上传类 POST),
$request_body变量常为空字符串 - 即使启用
client_body_buffer_size和client_max_body_size,body 内容仍可能被截断或转义 - 不同客户端发送相同逻辑数据,body 字符串可能因格式(空格、换行、字段顺序)不同而 hash 不同
- 含敏感字段(如密码、token)的 body 直接参与 key,会带来审计与合规风险
更稳妥的替代方案
核心思路:把“语义等价”的请求映射为唯一、稳定、可复现的标识,而不是依赖原始字节流。
-
前端改用 GET + query string:适合搜索、筛选等幂等场景。将 JSON 参数扁平化为 URL 参数(如
/api/search?category=book&price_min=20&tags=python,web),天然支持标准缓存机制 -
后端生成签名并透传到 header:让应用解析 POST body 后计算 SHA256 或 MD5 摘要,通过自定义响应头(如
X-Request-Sign: a1b2c3...)返回;Nginx 在fastcgi_cache_key中引用该 header:fastcgi_cache_key "$scheme$request_method$host$request_uri$upstream_http_x_request_sign"; -
按业务字段构造结构化 key:若 body 固定为 JSON 且字段明确(如
{"q":"nginx","page":1,"size":20}),可在 location 中用 map 模块提取关键字段:map $request_body $cache_q { default ""; "~\"q\":\"(?<q>[^\"]+)\"" $q; }</q>
再组合进 key:fastcgi_cache_key "$host$request_uri$q$page$size";
必须避开的坑
这些变量会让缓存失去共享意义,应从 key 中剔除:
-
$cookie_*、$sessionid:导致每个用户缓存一份,无法复用 -
$remote_addr、$http_user_agent:使同一请求在不同设备/IP 下产生不同 key -
$request_body或未经清洗的$args:不稳定、不可控、易冲突
关键是把缓存键从“原始输入”转向“业务语义”,靠后端配合或前端约定来保障一致性,而不是让 Nginx 硬扛不可靠的请求体解析。











