伪静态与缓存叠加易引发PATH_INFO丢失、缓存键错乱、Nginx提前返回静态文件等问题,根源在于服务器转发与缓存拦截时序错位,需分别在Apache/Nginx配置、框架缓存键生成及域名绑定场景中针对性修复。

伪静态和缓存本身不直接冲突,但两者叠加后,PATH_INFO解析失败、缓存键生成错乱、或路由未进框架就命中静态响应,会导致“URL能访问但数据不对”“缓存不更新”“404却无报错”等现象。问题核心不在框架配置,而在服务器转发与缓存拦截的时序错位。
Apache下.htaccess与文件缓存同时启用时PATH_INFO丢失
当 .htaccess 放在 public/ 目录且含标准重写规则,但 Cache::get() 读到的是旧缓存(比如模板或路由缓存),而该缓存是基于旧 $_SERVER['PATH_INFO'] 生成的,就会导致后续请求路由错配。
- 确认
.htaccess中 RewriteRule 是否带[QSA]:缺它会导致 query string 丢失,Cache::remember()闭包里取不到$_GET参数 - 检查
public/index.php开头是否加了var_dump($_SERVER['PATH_INFO']); die;,访问/user/123.html输出为空,说明 Apache 没传PATH_INFO—— 此时要补RewriteCond %{REQUEST_FILENAME} !-f和RewriteCond %{REQUEST_FILENAME} !-d,否则静态文件规则会提前截断 - 文件缓存驱动(
File)默认按完整 URL 哈希生成键,但伪静态后缀(如.html)若未被Url::build()或路由解析识别,缓存键可能和真实请求不一致;可在app.php中显式设'url_html_suffix' => 'html'并确保所有url()调用都走框架生成
Nginx中try_files触发静态缓存却绕过ThinkPHP
try_files $uri $uri/ /index.php?$query_string; 看似正确,但如果 runtime/cache/ 下恰好存在同名 .html 文件(比如静态缓存生成的页面),Nginx 会直接返回它,根本不会把请求交给 PHP —— 这就是“伪静态开着,缓存也开着,但改了控制器代码页面却不更新”的原因。
- 禁用 ThinkPHP 静态缓存(
'html_cache_on' => false),它和 Nginx 的try_files天然互斥,别混用 - 若必须保留 Nginx 层缓存,需在
location /块中排除所有伪静态后缀:例如location ~ \.(html|shtml|xml)$ { add_header X-Cached-By nginx; expires 10m; },再单独为 PHP 请求写location ~ \.php$块 - 验证是否真进框架:访问一个不存在的伪静态路径(如
/xyz123.html),若返回 Nginx 默认 404,说明try_files没 fallback 到/index.php;若返回 TP 的 404 页面,才说明请求已抵达框架,此时缓存问题才在应用层
域名绑定 + 伪静态 + 缓存三者共存时的键污染
当配置了 'domain_bind' => ['admin.example.com' => 'admin'],又开启请求缓存('request_cache' => true),不同域名下的相同路径(如 /user/list)会被缓存为同一个键,造成 admin 域名下显示前台用户列表。
立即学习“PHP免费学习笔记(深入)”;
- 必须在缓存键中注入域名信息:重写
Cache驱动的getCacheKey()方法,或手动拼接键,例如cache('user_list_' . $_SERVER['HTTP_HOST'], ...) - 避免使用全局
'request_cache',改用路由级缓存并绑定域名:Route::domain('admin.example.com')->rule('list', 'admin/User/list')->cache(3600); - 如果用了
Cache::tag(),标签名不能只写'user',得带上域名前缀,如Cache::tag('admin_user')->set(...),否则Cache::tag('user')->clear()会误清所有域名的数据
最易被忽略的是:伪静态后缀(如 .html)在 Request::ext() 中可读,但在缓存键生成逻辑里默认不参与 —— 如果你依赖 ext() 做条件分支,却没把它塞进缓存键,那所有后缀请求都会共享同一份缓存内容。



















