thinkphp路由失效或404的根本原因是web服务器未正确配置伪静态,导致请求未统一转发至public/index.php;nginx需在location /和location ~.php$中均配置try_files,apache需启用mod_rewrite并设置allowoverride all且.htaccess置于public目录下。

ThinkPHP 路由失效、404,其实是没配好伪静态
直接说结论:ThinkPHP 默认开启 URL 重写后,index.php 不是“可选”,而是必须被 Web 服务器拦截并转发给它处理;不配伪静态,所有 route 都会 404 或退化成 index.php?s=/xxx 这种丑陋路径。
核心不是 ThinkPHP 本身的问题,而是 Nginx/Apache 没把“看起来没有 index.php”的请求,正确转给 index.php 入口文件。常见错误现象包括:
- 点击菜单跳转后地址栏出现
index.php,且刷新页面直接 404 -
url()生成的链接带index.php,但手动删掉又打不开 - Apache 下开了
mod_rewrite,但.htaccess放错位置或权限被忽略
Nginx 配置:location ~ \.php$ 块里漏了 try_files
很多人只改 location /,却忘了 PHP 处理块本身也要配合——否则即使 URL 被重写进来了,Nginx 仍会按字面匹配 .php 文件,找不到就直接 404。
关键点在于:ThinkPHP 的入口是统一的 public/index.php,所有请求都得兜到这儿,而不是让 Nginx 去找一堆不存在的 .php 文件。
正确做法(在 server 块内):
location / {
try_files $uri $uri/ /index.php?s=$uri&$args;
}
location ~ \.php$ {
try_files $uri /index.php?s=$uri&$args;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
注意两个 try_files 行:$uri 是优先找真实文件/目录,失败才 fallback 到 /index.php?s=...;漏掉这句,Nginx 就不会把 /user/list 这种路由交给 index.php 处理。
常见坑:
-
root指向的是public/目录,不是项目根目录,否则$document_root/index.php会 404 - 使用
fastcgi_split_path_info的旧写法已过时,ThinkPHP 6+ 完全依赖s=参数传入路由,不用解析 PATH_INFO - 如果用了
alias而非root,$document_root可能为空,导致SCRIPT_FILENAME错误
Apache 配置:.htaccess 不生效?检查 AllowOverride 和 mod_rewrite
ThinkPHP 自带的 public/.htaccess 文件本身没问题,但 Apache 默认禁用目录级重写,所以你放了也没用。
必须确认两件事:
-
mod_rewrite已启用:a2enmod rewrite(Ubuntu/Debian)或检查httpd.conf中是否取消了#LoadModule rewrite_module modules/mod_rewrite.so的注释 -
AllowOverride All已加在站点配置的<directory></directory>块中,例如:<directory> AllowOverride All Require all granted </directory>
如果用 XAMPP/MAMP,AllowOverride 往往默认是 None,这是最常被忽略的一环。
另外,.htaccess 必须放在 public/ 目录下,且内容为:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?s=$1 [QSA,PT,L]
注意 QSA(保留原 query string)、PT(PassThrough,确保后续交给 PHP 处理),缺一不可。
ThinkPHP 配置项别忘关 PATH_INFO 模式
即使 Web 服务器配对了,ThinkPHP 如果还开着 url_pathinfo_convert 或强制用 PATH_INFO 解析,反而会导致重复解析或参数丢失。
在 config/app.php 中确认以下配置:
-
'url_route_on' => true(必须开,否则不走路由) -
'url_html_suffix' => ''(避免后缀干扰) -
'url_common' => false(禁用普通模式,即?s=风格) -
'url_pathinfo_fetch' => ['ORIG_PATH_INFO', 'REDIRECT_PATH_INFO']这类旧方式建议清空或注释,现代 Nginx/Apache 都走s=参数传递
TP6+ 默认就是 s= 模式,只要 Web 服务器把请求兜进来,框架自己就能解析。强行保留 PATH_INFO 适配,反而在 Nginx 下容易出空路由或 404。
最后提醒一句:Nginx 的 try_files 和 Apache 的 .htaccess 是互斥方案,别混着试;改完配置记得 nginx -t && systemctl reload nginx 或 apachectl graceful,别只改不重载。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










