将POST请求体作为NGINX缓存键的配置未按预期生效
我尝试将NGINX用作GraphQL服务器的反向代理并启用NGINX缓存功能。计划对POST API请求的响应进行缓存,同时将请求体和API URL纳入缓存键的组成部分,但配置未按预期工作:即使修改API请求的payload,仍会收到首次缓存的相同响应,不确定配置中存在什么问题。
现有配置
worker_processes 1; error_log C:/Workspace/error.log; events { worker_connections 1024; } http { # 定义缓存路径及设置 proxy_cache_path "C:/Users/username/Documents/cache" levels=1:2 keys_zone=my_cache:100m max_size=200m inactive=5m; limit_req_zone $binary_remote_addr zone=mylimit:10m rate=10r/m; include mime.types; default_type application/octet-stream; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; access_log logs/access.log main; sendfile on; keepalive_timeout 65; server { listen 8081; server_name localhost; location /api { proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host localhost; proxy_pass http://localhost:8080; # 启用请求体缓冲并设置缓冲区大小 proxy_buffers 8 32M; proxy_buffer_size 30M; client_body_buffer_size 10M; # 根据需求调整大小 # proxy_buffering on; # 启用代理缓冲 # proxy_ignore_headers "Set-Cookie"; # proxy_hide_header "Set-Cookie"; proxy_hide_header Cache-Control; proxy_cache_methods GET POST; # 基于请求协议、方法和URI定义缓存键 set $cache_key "$scheme$request_method$request_uri|$request_body"; # 根据x-api-cache头设置是否缓存的标志 set $cache_condition 0; if ($http_x_api_cache != "true") { set $cache_condition 1; } # 仅当条件为true时启用缓存 proxy_cache my_cache; proxy_cache_key $cache_key; proxy_cache_bypass $cache_condition; proxy_no_cache $cache_condition; proxy_cache_valid 200 5m; # 添加X-Cache-Status头显示缓存状态 add_header X-Cache-Status $upstream_cache_status; } } }
问题分析与修复方案
1. 请求体未被正确读取
NGINX默认在处理set指令时,可能还未完整读取请求体,导致$request_body变量为空或不完整,最终不同payload使用了相同的缓存键,出现缓存命中错误。
修复:取消注释proxy_buffering on;,开启代理缓冲功能。该配置会让NGINX先将请求体完整缓冲到内存或磁盘,确保$request_body能正确获取到完整的请求内容。
2. 缓存键优化(可选但推荐)
直接使用$request_body作为缓存键的一部分,可能因请求体的格式差异(如空格、换行)导致不必要的缓存键差异,同时过长的请求体也会导致缓存键体积过大。建议使用NGINX 1.17.9及以上版本支持的$request_body_hash变量,对请求体进行哈希处理:
set $cache_key "$scheme$request_method$request_uri|$request_body_hash";
这样相同内容的请求体(无论格式)会生成相同哈希,不同内容则生成不同哈希,既保证缓存区分度,又优化缓存键长度。
3. 缓存条件逻辑验证
当前配置的缓存条件逻辑是:仅当请求头x-api-cache=true时才会使用缓存并存储响应。如果你的需求是默认缓存POST请求,仅在特定头下跳过缓存,需要调整逻辑:
set $cache_condition 0; if ($http_x_api_cache = "false") { set $cache_condition 1; }
这样只有当x-api-cache=false时,才会跳过缓存并不存储响应,其余情况正常缓存。
4. 缓存目录权限检查
Windows环境下需确保NGINX进程对C:/Users/username/Documents/cache目录有读写权限,否则缓存无法正常写入,可能导致始终返回旧缓存或无法缓存。
内容的提问来源于stack exchange,提问作者Rohit Kumar

