TP6.0路由404主因是APP_DEBUG未关闭导致缓存失效;需确认config/app.php中'app_debug'=>false,清空runtime/route/并执行php think route:cache --annotation;动态路由须置于app/route.php顶层或用Route::import,避免写在运行时逻辑中。
TP6.0 路由缓存只在 APP_DEBUG=false 时生效;只要 thinkApp::debug() 返回 true,哪怕你刚生成了 runtime/route.php,框架也会跳过缓存、重新解析所有路由文件——此时你改了 route/app.php 却没生效,大概率是调试模式还开着。
检查方式:在任意控制器里加 dump(thinkApp::debug());,输出 true 就说明没关掉。注意:.env 中设 APP_DEBUG=false 不保险,最终以 config/app.php 里的 'app_debug' => false 为准。CI/CD 构建后若漏改此项,上线即失效。
php think route:cache 前没清旧缓存或漏参数缓存命令不会自动覆盖或清理旧文件,runtime/route/ 目录残留空文件、损坏数组或旧版本内容,会导致新路由不载入。同时,注解路由(@Route)默认不扫描,必须显式加 --annotation 参数,否则 route:cache 只处理 route/app.php 这类 PHP 文件。
rm -rf runtime/route/
php think route:cache --annotation
app/controller/ 下的类,命名空间错位、文件名大小写不符(Linux 敏感)、use 别名引入都会导致漏扫#[Route])在 TP 6.0.x 中不支持缓存,得降级为 PHPDoc 注解Route::rule() 或从数据库读取的动态路由,如果写在控制器方法、事件监听器、闭包里,route:cache 命令运行时根本不会执行它——缓存只序列化静态结构,不跑运行时逻辑。
正确做法是把动态路由注册逻辑提到 app/route.php 文件顶层,确保命令执行时能立即执行并返回完整路由数组。或者改用 Route::import('path/to/dynamic_routes.php'),该 PHP 文件可含简单逻辑(如读 JSON),但禁止 DB 查询、HTTP 请求等阻塞操作。
验证是否进缓存:运行 php think route:list,输出里没你的动态路由,说明缓存阶段就没注册进去。
permit ip any any 或伪静态干扰多应用模式下,访问 /admin/getlog 必须带上模块名,即实际路径是 /index.php/admin/getlog;若没配伪静态,直接访问会 404。另外,部分用户误将 ACL 思维套到路由上:比如在 route/app.php 顶部写了 Route::any('/', function () { return 'home'; });,后面所有规则都匹配不到——因为 any 通配优先级最高。
常见干扰点:
index.php,例如 http://hml.tp6.com/index.php/admin/getlog
Route::get('user/:id', ...) 要放在更宽泛的规则(如 Route::get('user/*', ...))之前真正难排查的,是缓存文件存在但内容为空、或被旧逻辑污染——这时候 route:list 看不到任何路由,连基础 / 都 404,得盯住 runtime/route.php 文件本身是否可读、是否真包含有效数组。