404主因是请求未进入thinkphp路由系统,需优先排查web服务器重写配置、入口文件接管及路由注册位置;加/index.php能访问即伪静态未生效。

刚跑通ThinkPHP项目,一访问/user/list就报404,但加个/index.php就能打开——这不是你路由写错了,而是请求压根没进到框架里,Web服务器直接返回了原生404,ThinkPHP连初始化都没机会执行。
确认请求是否真正进入ThinkPHP
第一步:在浏览器访问 http://localhost/index.php/route/test(确保该路由未定义),如果看到ThinkPHP调试页提示「找不到路由」,说明框架已接管;如果直接返回Nginx/Apache原生404页面,且响应头里没有X-Powered-By: ThinkPHP,那就停在这里别往下调路由代码了——问题出在入口接管环节。
第二步:用命令行验证路由注册快照:php think route:list。输出为空、或列表里根本没有你写的/user/list,代表route/app.php根本没被执行。此时在route/app.php第一行加die('route loaded');,刷新任意URL,没中断=该文件被跳过。
第三步:检查config/app.php中'url_route_on' => true是否被环境变量覆盖——尤其注意.env里有没有APP_URL_ROUTE_ON=false这类隐藏开关。
Apache用户:.htaccess没生效的典型表现
方法一:确认public目录下存在.htaccess文件,内容必须包含标准重写规则,例如:
RewriteEngine On<br>RewriteCond %{REQUEST_FILENAME} !-d<br>RewriteCond %{REQUEST_FILENAME} !-f<br>RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
方法二:最关键的一步——检查Apache配置中对应目录的<directory></directory>块是否设置了AllowOverride All。只写AllowOverride FileInfo或漏掉这行,.htaccess会被完全忽略,所有重写失效。
【Linux服务器上,.htaccess文件名必须全小写,写成.Htaccess或HTACCESS会直接失效】
Nginx用户:伪静态配置的三个致命坑
① location / 块内必须有且仅有一条try_files指令:try_files $uri $uri/ /index.php?$query_string;。缺$query_string会导致?id=123参数丢失,$_GET为空;写成/index.php?s=是TP5旧写法,TP6/TP8不兼容。
② fastcgi_param SCRIPT_FILENAME 必须设为$document_root$fastcgi_script_name,绝不能用$request_filename——后者在重写后可能指向错误路径,导致PHP解析失败。
③ 子目录部署(如https://site.com/myapp/)时,location必须匹配前缀:location /myapp/ { try_files $uri $uri/ /myapp/index.php?$query_string; },同时在config/app.php里设置'app_host' => 'https://site.com/myapp',否则URL生成全错。
路由定义本身失效的隐蔽原因
方法1:别在控制器构造函数、模型init()方法或中间件handle()里调用Route::get()——此时think\facade\Route类尚未初始化,调用静默失败,无任何报错。
方法2:多应用模式下,路由必须写在app/multi/your_app_name/route/app.php,而不是根目录的route/route.php。写错位置等于没写。
方法3:大小写陷阱——Windows开发时访问/User/List能通,Linux上线立刻404。ThinkPHP默认区分大小写,而前端AJAX请求拼的URL、Vue Router生成的路径、甚至里的href,都必须和Route::get('/user/list')中的路径**逐字符一致**。
开启强制路由后静态资源全404
当'url_route_must' => true启用时,/static/css/app.css这种请求会被当成动态路由去匹配,找不到就直接404。解决方法只有一条:在route/app.php最顶部插入显式放行规则:
Route::rule(':path^.*\.(js|css|png|jpg|gif|svg|woff2|ttf)$', 'static/:path', 'GET', ['ext' => '']);
【['ext' => '']这个参数不可省略,否则ThinkPHP会自动给/a.js补.html后缀,导致匹配失败】
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











