ThinkPHP 5 绑定域名后,访问控制器直接报 404,最常见的误判就是一上来去改路由文件、控制器名甚至方法名。实际上,这类问题往往先要看请求有没有被 Web 服务器正确转交给 public/index.php,因为只要请求没进框架,后面的路由、模块和控制器检查基本都没有意义。本文按入口验证、站点根目录、路由加载和 Nginx PATH_INFO 这几个层次来排查,读完你可以更快判断问题究竟落在服务器配置,还是落在 ThinkPHP 5 本身。
先确认请求有没有进入 ThinkPHP 入口
ThinkPHP 5 域名绑定后访问控制器返回 404,大概率不是路由写错了,而是请求压根没进到框架的路由层。这个阶段去改 route/route.php 或控制器方法名,通常不会解决问题。

最直接的办法,是先访问一个带入口文件的地址:
http://your-domain.com/index.php/index/index
前提是该控制器方法本身存在。如果这个地址能正常打开,说明框架至少已经跑起来了;如果这里仍然是 404,而且响应头里看不到 X-Powered-By: ThinkPHP,那问题多半不在 PHP 代码,而在 Web 服务器配置。
也可以用命令行快速判断:
curl -I http://localhost/index.php/index/index
如果响应头里有 X-Powered-By,再继续检查框架层配置;如果只有 Server: nginx 或 Server: Apache,通常说明 PHP 进程根本没有执行,请求在 Web 服务器这一层就被拦住了。
这一步建议优先检查下面几项:
- Apache 环境:确认
public/.htaccess存在,文件名为全小写,内容是标准重写规则;同时对应的Directory块里要启用AllowOverride All - Nginx 环境:确认
server块中的root指向项目的public/目录,而不是项目根目录 - 宝塔环境:进入站点设置里的运行目录,必须选择
/public,注意是带斜杠的路径;修改后要保存并重启
域名绑定后,重点检查文档根目录是否指向 public
ThinkPHP 5 默认入口是 public/index.php。如果域名绑定时直接把站点根目录设成项目根目录,例如 /var/www/your-project/,却没有继续指向 public/,那么访问 http://your-domain.com/index/index 时,请求实际上不会按框架入口走,而是被服务器当成物理路径去查找文件。
这时服务器可能会尝试寻找类似下面的位置:
/var/www/your-project/index/index.php
由于这个物理路径并不存在,Nginx 或 Apache 就会直接返回 404。也就是说,看起来像“控制器找不到”,本质上却是“入口路径错了”。
这一层可以按下面的顺序核对:
- 在 Linux 下执行
ls -l /var/www/your-project/public/index.php,确认入口文件真实存在 - Apache 的
DocumentRoot必须设置为/var/www/your-project/public - Nginx 的
root必须是/var/www/your-project/public,不能漏掉/public - 检查
public/index.php中的define('APP_PATH', __DIR__ . '/../application/');,确保入口文件回溯上一层后,确实能定位到application/目录
如果这里配置正确,再去看路由和控制器才有意义;如果这里配置不对,后面的排查基本都会被误导。
再看路由是否加载、控制器是否能被正确识别
当确认请求已经进入 index.php 之后,下一步才轮到 ThinkPHP 5 自身的路由和控制器配置。
可以先执行:
php think route:list
如果输出为空,或者看不到你定义的 index/index,说明 route/route.php 很可能没有被正常执行。为了进一步确认,可以临时在该文件第一行加入:
die('route loaded');
刷新任意 URL 后,如果页面没有中断,说明这个文件根本没被加载到,问题就不在路由内容写得对不对,而在加载链路本身。
这一节建议继续核对几个容易忽略的点:
config/app.php中的'url_route_on' => true是否已经开启- 控制器文件名和类名大小写是否一致,尤其在 Linux 环境下,
Index.php和index.php会被当成两个不同文件 - 控制器方法必须是
public,如果写成protected或private,外部请求无法访问 - 如果项目使用模块,例如
admin,要确认域名绑定时没有漏掉模块前缀,或者已经在路由中显式声明模块
很多“控制器 404”最后其实不是框架 bug,而是文件名大小写、方法可见性或模块前缀这种很细的配置问题。
Nginx 下别漏掉 PATH_INFO 支持
如果前面的入口、文档根目录和路由加载都没问题,但访问方式一换就出现 404,还要特别留意 Nginx 的 PATH_INFO 兼容性。

ThinkPHP 5 默认使用 PATH_INFO 模式解析 URL,例如:
/index.php/Index/Index/index
部分旧版环境或精简 Nginx 配置并不会默认把这段路径信息正确传给 PHP。结果就是:看起来请求经过了 index.php,但框架实际上拿不到控制器和方法,于是直接判定为 404。
在 Nginx 的 location ~ .php$ 配置块中,通常需要包含下面两行:
fastcgi_split_path_info ^(.+.php)(/.+)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
这两行缺一不可。少了 fastcgi_split_path_info,$fastcgi_path_info 就可能是空值;而 PATH_INFO 没有传进去,ThinkPHP 5 就拿不到完整的 URL 解析结果。
这个问题之所以常见,是因为很多教程只给出 try_files 配置,却没有提醒 TP5 对 PATH_INFO 的依赖。于是表面看像是路由异常,实际却是 Nginx 到 PHP-FPM 之间少传了一段关键参数。
一个更省时间的排查顺序
遇到 ThinkPHP 5 域名绑定后控制器 404,建议按固定顺序处理:先访问 /index.php/index/index 确认请求是否进入框架,再检查站点根目录是不是明确指向 public/,然后核对路由加载、控制器大小写与方法可见性,最后再回到 Nginx 的 PATH_INFO 配置。
这样排查的好处是可以先区分“服务器没把请求交给 TP5”和“TP5 已收到请求但解析失败”这两大类问题。只要先把这一层判断清楚,后面的修复通常会快很多,也能避免在错误方向上反复改代码。













