强制路由访问不到的主因是请求未进入路由匹配环节,需依次检查Web服务器重写配置、入口文件加载、url_route_on开关、静态资源别名、路由缓存清理及m/c/a参数拦截。

强制路由开启后访问不到,大概率不是路由规则写错了,而是请求根本没进到路由匹配环节——90% 的问题卡在 Web 服务器重写配置或入口接管上。
先确认请求是否进了 ThinkPHP
直接访问 http://localhost/index.php/route/test(确保该路由未定义)。如果看到 ThinkPHP 的「Route not found」提示页,说明框架已加载、路由系统在运行;如果返回 Nginx/Apache 原生 404 页面,且响应头里没有 X-Powered-By: ThinkPHP,那就别调路由文件了,问题出在入口层。
- 用命令行执行
php think route:list,输出为空或不包含你写的规则 →route/app.php没被加载 - 在
route/app.php第一行加die('loaded');,刷新任意 URL 看是否中断 → 不中断 = 文件被跳过 - 检查
config/app.php中'url_route_on' => true是否启用,它关了,url_route_must就完全无效
静态资源全 404?别改 Nginx,先补路由别名
强制模式下,/static/logo.png 这类路径也会被当成动态路由去匹配,找不到就 404。这不是服务器问题,是框架默认不识别静态路径。
- 在
route/app.php最顶部(早于任何Route::get())加:Route::alias('static', 'static'); - 同理加
Route::alias('js', 'js')和Route::alias('css', 'css'),注意大小写与 Linux 部署环境一致 - 更可控的做法:用
Route::rule()显式匹配后缀:Route::rule(':path^.*\.(js|css|png|jpg|gif|svg|woff2|ttf)$', 'static/:path', 'GET', ['ext' => '']),['ext' => '']关键,否则/a.js可能被误补成/a.js.html
清缓存这事不能“清空文件夹”了事
runtime/route/ 目录必须整个删掉,不是只删里面文件。ThinkPHP 编译后的路由缓存含目录结构和命名空间信息,残留旧文件会导致新配置不生效。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
立即学习“PHP免费学习笔记(深入)”;
- 删完后,访问任意 URL(比如
/)触发重建,再跑php think route:list确认输出是你刚写的规则 - 顺手也清一下
runtime/cache/,避免其他缓存干扰验证 - 如果用了
.env,确认APP_DEBUG=true,否则 404 错误会被静默吞掉,看不到具体提示
还漏了一个硬拦截:m/c/a 参数绕过路由
即使开了 url_route_must,带 ?m=index&c=index&a=index 的请求仍可能被底层解析。这不是 bug,是历史兼容逻辑残留。
- 在
app/common.php或app/event.php里注册app_init事件监听器 - 插入校验:
if (input('m') || input('c') || input('a')) { throw new \think\exception\HttpException(404); } - 必须放在所有中间件和路由注册之前,否则拦截时机太晚
真正麻烦的不是哪条路由怎么写,而是你不确定请求到底走到哪一步了——看响应头有没有 X-Powered-By,看 route:list 输出有没有你的规则,看 runtime/route/ 是不是彻底空的。这三个点对上了,剩下的就是语法细节问题。


















