ThinkPHP5二级目录伪静态失效的根本原因是服务器未将请求正确转发至子目录入口文件,导致框架未获取PATH_INFO或s参数;需配置RewriteBase(Apache)或精准location+rewrite(Nginx),并关闭URL_MODEL干扰、清理缓存。

ThinkPHP5 二级目录部署时伪静态失效的典型表现
访问 http://example.com/subdir/index/index 返回 404,但加 index.php 就能通(如 http://example.com/subdir/index.php/index/index);或者所有路由都跳到首页、public 目录被当成普通路径暴露出来。根本原因不是规则写错了,而是 Apache/Nginx 没把请求正确“转发进”子目录里的入口文件,框架压根没收到 PATH_INFO 或 s= 参数。
Apache 下 .htaccess 必须加 RewriteBase
二级目录(比如项目放在 /var/www/html/myapp/,实际访问地址是 http://site.com/myapp/)时,.htaccess 不能直接套用根目录规则。否则重写后的路径会错位,$1 匹配到的是完整 URL 路径,而框架只认子目录内的相对路径。
- 确保
.htaccess放在子目录根(即和index.php同级),内容为:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /myapp/
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>
-
RewriteBase /myapp/是关键,必须和你实际访问的 URL 前缀完全一致(结尾斜杠不能少) - 如果项目结构是
myapp/public/index.php,则RewriteBase应为/myapp/public/,且index.php路径要同步调整 - Apache 虚拟主机配置中仍需确认
AllowOverride FileInfo Options,否则RewriteBase不生效
Nginx 子目录伪静态要用 if + rewrite,且 location 必须精准
宝塔或手动配 Nginx 时,try_files 在二级目录下容易误判 $uri,导致静态资源也被甩给 index.php。更可靠的是显式判断文件不存在后重写,并限定作用域。
- 在站点配置的
server块内,添加独立的location块(不要塞进根location /里):
location /myapp/ {
if (!-e $request_filename) {
rewrite ^/myapp/(.*)$ /myapp/index.php?s=/$1 last;
}
}
-
last不可换成break:否则重写后不重新匹配 PHP 处理块,请求卡死在静态流程 - 若入口在
public目录(TP5.1+ 常见),则路径要对齐:rewrite ^/myapp/(.*)$ /myapp/public/index.php?s=/$1 last; - 务必检查 Nginx 的
root指向是否包含/myapp,否则$request_filename判断永远为 false
ThinkPHP5 配置里得关掉 URL_MODEL=0 的干扰
很多人在 config.php 里设了 'URL_MODEL' => 2,却忘了 TP5 默认兼容三种模式,而二级目录下 PATH_INFO 解析极易出错。最稳的方式是强制走 s= 参数模式,和服务器规则对齐。
立即学习“PHP免费学习笔记(深入)”;
- 在
config/app.php中明确设置:
'url_route_on' => true, 'url_common_param' => false, 'url_html_suffix' => '.html', 'pathinfo_depr' => '/',
- 删掉或注释掉
'URL_MODEL' => 2—— 这个配置项在 TP5.1+ 已被废弃,留着反而触发旧兼容逻辑 - 确保
route/route.php里定义的规则不依赖绝对路径,例如用Route::rule('news/:id', 'index/news/read');,而不是硬编码/myapp/ - 如果用了多模块,检查
app/multi_app.php是否把子目录名当成了应用名,造成路由前缀错乱
二级目录伪静态真正卡住的地方,往往不在规则本身,而在「服务器认定的请求路径」和「框架解析出的 PATH_INFO」之间差了一个目录层级。每次改完都要清空 runtime/cache/,否则旧路由缓存会掩盖配置生效状态。



















