ThinkPHP伪静态需服务器规则、框架路由、入口路径三者严格对齐:Apache用含index.php/$1和QSA的.htaccess规则,Nginx推荐try_files写法,框架须开启url_route_on、统一pathinfo_depr,且Web根目录必须为public/。

ThinkPHP 伪静态不是光改个 .htaccess 就能跑通的,服务器重写规则、框架路由开关、入口路径三者必须对齐,缺一不可。常见 404 或跳回 index.php 的问题,90% 出在这三处没配平。
Apache 下 .htaccess 规则怎么写才不丢参数
最简可用的规则是:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
注意三点:
-
index.php/$1中的/是关键分隔符,TP5/6 默认用它解析 PATH_INFO;若你改过pathinfo_depr配置(比如设成-),这里也得同步改成index.php-$1 -
QSA必须保留,否则 URL 后带的查询参数(如?from=weibo)会丢失 - 如果项目不在 Web 根目录(比如部署在
/myapp/),必须加RewriteBase /myapp/,且RewriteRule目标要对应调整为/myapp/index.php/$1 - Apache 要确认
AllowOverride FileInfo Options已启用,仅All不够稳妥,某些发行版会限制模块权限
Nginx 用 try_files 还是 if?推荐前者
if (!-e $request_filename) 看起来直观,但 Nginx 官方明确不建议在 location 块中使用 if,容易触发未定义行为(比如重写后 $args 消失、POST 数据截断)。
立即学习“PHP免费学习笔记(深入)”;
正确写法是:
location / {
try_files $uri $uri/ /index.php?s=$uri&$args;
}
关键点:
-
try_files是原子操作,优先尝试真实文件/目录,失败才 fallback 到index.php -
s=$uri对应 ThinkPHP 的默认 PATH_INFO 解析方式;如果你在config/app.php中设了'pathinfo_fetch' => ['QUERY_STRING'],就得改成/index.php?$uri&$args -
&是 HTML 实体,在 Nginx 配置里必须写成&,否则配置校验失败 - 确保
fastcgi_param SCRIPT_FILENAME指向的是public/index.php(TP6 默认结构),而不是根目录下的index.php
ThinkPHP 自身配置哪些项不能漏
光有服务器规则,框架层关着路由也没用。检查以下几项是否生效:
-
'url_route_on' => true:必须开启,TP6 默认为true,但 TP5 仍需手动打开 -
'url_html_suffix' => 'html':非必需,但设为空字符串''可兼容任意后缀(如.xml、.pdf),方便做内容格式切换 -
'pathinfo_depr' => '/':和服务器规则中的分隔符严格一致,改了就要两边同步 -
'app_debug' => false:调试模式下部分重写可能被绕过,上线前务必关闭
TP6 中还多一个隐性开关:public/ 必须是 Web 服务器的实际运行目录,否则 index.php 找不到自动加载器,直接报错而非 404。
宝塔面板或 IIS 下容易忽略的细节
宝塔用户常以为选了“ThinkPHP”伪静态模板就万事大吉,其实:
- Apache 模式下,宝塔生成的规则默认用
RewriteRule ^(.*)$ index.php [QSA,PT,L]—— 缺少/$1,会导致所有请求都进首页,路由参数全丢 - Nginx 模式下,宝塔模板有时漏掉
$args,造成 GET 参数丢失,需手动补上&$args - IIS 用户必须用
web.config,且<rule name="OrgPage">的match和action要完整,常见错误是只写了match没写action type="Rewrite" - 所有环境都要确认:Web 服务器工作目录 =
public/,不是项目根目录;否则index.php加载的自动加载路径会错乱
最隐蔽的坑是:Nginx + PHP-FPM 组合下,PATH_INFO 可能被 FPM 截断,需要在 fastcgi_params 里显式设置 fastcgi_split_path_info ^(.+?\.php)(/.*)$; 并启用 fastcgi_param PATH_INFO $fastcgi_path_info;。



















