目录级缓存需用$uri而非$request_uri并统一尾部斜杠,通过正则提取路径前缀(如$dir_level)构造cache_key,配合fastcgi_ignore_headers、map跳过用户请求及按目录设置cache_valid实现。

要利用 fastcgi_cache_key 整合 $request_uri 实现目录级缓存,核心在于让缓存键(cache key)能区分不同目录层级的请求,同时忽略同一目录下因参数、会话等带来的干扰。关键不是简单拼接变量,而是有意识地“截断”或“归一化” URI 到目录级别。
明确目录级缓存的目标
目录级缓存指:例如 /blog/ 下所有请求(如 /blog/、/blog/post123、/blog/tag/nginx?sort=date)共用一个缓存实体,只要内容由同一逻辑生成(比如 WordPress 的 blog 首页模板),就应命中同一个缓存项。这要求 cache key 对路径前缀敏感,对查询参数、尾部斜杠、大小写等保持宽容。
构造符合目录语义的 cache_key
直接使用 $request_uri 会导致每个带参数或不同大小写的 URL 都生成独立缓存,违背目录级目标。应提取“目录根路径”,常用做法是用正则捕获第一级或前两级路径:
- 仅缓存一级目录(如
/shop/、/api/):fastcgi_cache_key "$scheme://$host$uri/";
(注意:这里用$uri而非$request_uri,它不带参数;末尾加/统一目录形式) - 更精准控制(如只取前两级路径):
set $dir_level "";if ($uri ~ "^(/[^/]+/[^/]+/)") { set $dir_level $1; }if ($uri ~ "^(/[^/]+/)") { set $dir_level $1; }fastcgi_cache_key "$scheme://$host$dir_level"; - 强制统一尾部斜杠(避免
/about和/about/分裂缓存):if ($uri !~ /$) { rewrite ^(.*)$ $1/ permanent; }
或在 cache_key 中统一处理:fastcgi_cache_key "$scheme://$host${uri}/";
配合其他指令确保缓存有效性
仅改 key 不够,还需关闭干扰因素:
- 忽略查询参数影响:
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
(防止后端响应头禁用缓存) - 跳过用户相关请求(如登录态、AJAX):
map $request_uri $skip_cache {~*^/(wp-admin|login|admin) 1;~*\.(php|jsp|cgi)$ 1;default 0;}
然后在 location 中:fastcgi_cache_bypass $skip_cache; - 设置合理缓存时间(按目录策略):
location /blog/ {fastcgi_cache_valid 200 301 302 1h;# 其他 fastcgi_* 指令...}
验证与调试技巧
启用缓存后,通过响应头确认是否生效:
- 添加日志记录缓存状态:
log_format cache '$remote_addr - $remote_user [$time_local] '"$request" $status $body_bytes_sent ''"$http_referer" "$http_user_agent" "$http_x_forwarded_for" ''$upstream_cache_status'; - 检查
$upstream_cache_status值:HIT(命中)、MISS(未命中)、BYPASS(被跳过)、EXPIRED(过期) - 临时开启 debug 日志(谨慎用于测试环境):
error_log /var/log/nginx/cache_debug.log debug;
可看到 key 计算过程和匹配详情










