根本原因是Nginx未将非静态请求转发至index.php,导致ThinkPHP路由无法解析;需通过try_files或rewrite规则将请求重写到入口文件,并确保fastcgi_param PATH_INFO正确传递。

不是ThinkPHP代码错了,是Nginx根本没把请求交给index.php处理。所有“控制器404”“路由不生效”“/index/index报404但/index.php?s=/index/index能通”的现象,95%以上都卡在这一步——Nginx配置漏了关键转发逻辑。
为什么直接访问 /index.php 能通,但 /index/index 就 404
因为Nginx默认行为是:先查文件系统里有没有叫 index 的目录、有没有叫 index/index 的文件。没有就直接返回404,压根不会去调用 index.php。ThinkPHP的路由解析根本没机会运行。
常见错误现象:
- 首页
/index.php正常,/index/index报 404 -
/index.php?s=/index/index能返回内容,但去掉?s=就挂 - 开启
APP_DEBUG = true后只显示“Route not found”,没真实错误堆栈
本质是:Nginx没把非静态资源请求重写到入口文件。解决方案只有两个方向——try_files 或 rewrite,选一个配对即可,别混用。
立即学习“PHP免费学习笔记(深入)”;
Nginx location 块必须匹配实际部署路径
如果你把项目放在二级目录(比如 https://example.com/myapp/),location / { ... } 是错的。它会把 /myapp/index/index 当作根路径处理,导致 $_SERVER['REQUEST_URI'] 变成 /index/index,而框架实际需要的是 /myapp/index/index 才能正确剥离前缀。
实操要点:
- 显式写
location /myapp/ { ... },不能省略末尾斜杠 -
alias指向物理路径的public/目录,例如alias /var/www/html/myapp/public/; - 内部
location ~ \.php$中,fastcgi_param SCRIPT_FILENAME $request_filename;必须存在,且$request_filename要能拼出真实路径 - 必须有
fastcgi_param PATH_INFO $fastcgi_path_info;,否则/index/index中的/index/index段不会传进 PHP
漏掉任意一条,PATH_INFO 就为空,think\Route 解析不到控制器名。
伪静态规则选 try_files 还是 rewrite
try_files 更安全、性能更好,推荐优先用;rewrite 兼容旧版 Nginx,但容易和 if 嵌套产生意外交互。
推荐配置(根目录部署):
location / {
try_files $uri $uri/ /index.php?$query_string;
}
对应 PHP-FPM 处理块内必须含:
fastcgi_split_path_info ^(.+\.php)(/.+)$;fastcgi_param PATH_INFO $fastcgi_path_info;fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
如果用 rewrite(如宝塔面板常用):
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php?s=$1 last;
}
注意:last 表示内部重定向,break 会终止后续匹配——这里必须用 last,否则 index.php 不会被当作 PHP 脚本执行。
二级目录下 PATH_INFO 丢失是最隐蔽的坑
很多配置看着都对,但就是路由不生效。检查 $_SERVER['PATH_INFO'] 是否为空——只要它是空的,ThinkPHP 6 就无法识别控制器和方法名。
验证方法:在 public/index.php 开头加一行:
var_dump($_SERVER['PATH_INFO']); die();
然后访问 /myapp/index/index,如果输出 NULL 或空字符串,说明 fastcgi_param PATH_INFO 没生效,或者 fastcgi_split_path_info 正则没匹配上。
此时重点核对:
- Nginx 版本是否低于 1.10?低版本对
$fastcgi_path_info支持不稳定 -
fastcgi_split_path_info正则是否写成^(.+\.php)(/.+)$(注意开头无/) - 是否在子目录
location块里重复写了fastcgi_param PATH_INFO,但值写成了$1或硬编码路径
PATH_INFO 一旦为空,所有基于 PathInfo 模式的路由都会失效,且错误表现和配置错误高度相似——这是最常被跳过的排查点。



















