ThinkPHP 404需先区分是Web服务器还是框架路由问题:看响应头有无X-Powered-By: ThinkPHP;Nginx须将root设为public目录并配置try_files;开启url_route_must后需显式放行静态资源路由;控制器命名、大小写、命名空间须严格符合PSR-4规范。

ThinkPHP 报 404 页面不存在,绝大多数情况不是控制器写错了,而是请求压根没进框架——你看到的其实是 Nginx 或 Apache 的原生 404,不是 ThinkPHP 的「找不到路由」黄页。先确认这一点,再往下查。
怎么判断是 Web 服务器 404 还是 ThinkPHP 路由 404
打开浏览器开发者工具 → Network 标签页 → 刷新页面 → 看响应状态码和 Response Headers:
- 如果
Status是404 Not Found且Response Headers里没有X-Powered-By: ThinkPHP,说明请求根本没走到public/index.php,是 Web 服务器直接返回的 404 - 如果能看到黄色调试页、URL 中带
__debug__参数、或 Header 里有X-Powered-By: ThinkPHP,说明已进入框架,问题出在路由注册或控制器加载环节
前者要调 Web 服务器配置,后者才需要翻 route/app.php 或控制器文件。
Nginx 下 public 目录没设成 root 导致 404
这是线上部署最常踩的坑:Nginx 的 root 指向了项目根目录(如 /var/www/myapp),但 ThinkPHP 入口在 public/index.php。结果所有请求都去查 /var/www/myapp/xxx,当然 404。
立即学习“PHP免费学习笔记(深入)”;
正确做法是把 root 指向 public 子目录:
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
location / {
root /var/www/myapp/public;
try_files $uri $uri/ /index.php?$query_string;
}
注意:try_files 必须写在 location / 块里,不能放在 server 级;改完记得 nginx -t && systemctl reload nginx。
开启强制路由后静态资源全部 404
当 config/app.php 中设置了 'url_route_must' => true,ThinkPHP 会拦截所有请求,包括 /static/css/app.css —— 它不会自动识别后缀,只会按路由规则匹配。没匹配上就直接 404。
解决方式不是关掉强制路由,而是显式放行静态路径:
- 在
route/app.php最顶部(早于其他Route::get())加:Route::rule(':path^.*\.(js|css|png|jpg|gif|svg|woff2|ttf)$', 'static/:path', 'GET', ['ext' => '']) -
['ext' => '']关键:禁用后缀自动补全,否则/a.js可能被当成/a.js.html - 改完立刻清空
runtime/route/和runtime/cache/,否则旧缓存还在生效
别依赖 Route::alias('static', 'static'),它隐含假设路径结构固定,CDN 或动静分离时容易失效。
控制器存在但报 404:命名与命名空间不一致
ThinkPHP 6 默认使用 PSR-4 自动加载,控制器类名和文件路径必须严格对应:
- 类
app\controller\UserController必须放在app/controller/UserController.php - 方法名必须是
public,且不能带下划线前缀(_initialize是钩子,_empty是兜底,但不是可访问动作) - 如果用了多应用模式,检查
app/multi_app.php是否启用了对应应用,以及 URL 是否带了应用名前缀(如/admin/user/index)
最容易忽略的是:Linux 下文件系统区分大小写,usercontroller.php ≠ UserController.php,本地 Windows 开发没问题,一上 Linux 就 404。


















