开启ThinkPHP路由严格模式需设置'url_route_must'=>true,并清理runtime/route缓存;若仍可访问m/c/a参数URL,应在app_init事件中添加输入过滤强制拦截。

ThinkPHP 路由严格模式怎么开
默认情况下,ThinkPHP 会把 index.php?m=home&c=user&a=login 这类 URL 当作合法请求,即使你写了路由规则,它也照常执行——这不是“路由没生效”,是根本没进路由匹配流程。要让框架只认你定义的路由、拒绝所有 m/c/a 参数拼接的访问,必须开启路由严格模式。
关键配置在 config/route.php(或 app/config.php 中的 route 配置块):
return [
'url_route_must' => true, // 必须匹配路由规则才放行
'url_route_on' => true, // 确保路由功能已启用
];
注意:url_route_must 是核心开关,设为 true 后,任何未被路由规则捕获的请求都会直接抛出 HttpException(状态码 404),包括带 m/c/a 的传统 URL。
为什么开了 url_route_must 还能访问模块控制器
常见错误是只改了配置,但没清理运行时缓存。ThinkPHP 的路由规则在首次加载后会被编译缓存到 runtime/route 目录下,旧缓存不清理,新配置就不起作用。
立即学习“PHP免费学习笔记(深入)”;
实操建议:
- 删掉
runtime/route/整个目录(不是只清空,是删文件夹) - 确保没有在
app/middleware.php或中间件里手动调用think\App::module()绕过路由 - 检查是否在
config/app.php中设置了'app_multi_module' => false,单模块模式下m=xxx参数本不该生效,但如果路由未严格拦截,仍可能被底层解析
禁用 m/c/a 参数的底层动作
仅靠 url_route_must 不够彻底——它拦的是“没匹配到路由”的请求,但如果你的路由规则里用了闭包或动态变量,又或者写了类似 Route::get('user/:id', 'user/read') 这种,框架内部仍可能回退解析 c/a。真正堵死入口,得从参数解析层下手。
在应用初始化阶段(如 app/common.php 或全局中间件中)加一段过滤:
if (input('m') || input('c') || input('a')) {
throw new \think\exception\HttpException(404, 'Direct module/controller/action access denied');
}
这段代码必须放在路由匹配之前执行(比如注册为 app_init 事件监听器),否则路由已执行完毕,再拦就晚了。它比配置更硬核,但代价是每次请求多一次判断,对性能无实质影响。
兼容性与调试陷阱
开启严格路由后,以下情况会立刻暴露问题:
- AJAX 请求里还带着
?m=api&c=order&a=list—— 改成标准 RESTful 路径,比如/api/order/list - 模板里写死了
url('user/login')却没定义对应路由规则 —— 生成的 URL 会变成空或报错,必须补全Route::get('login', 'user/login') - 使用
Url::build()时传入数组参数如['m'=>'admin','c'=>'index','a'=>'dashboard']—— 这种写法在严格模式下会失效,应改为命名路由或规范路径
最容易被忽略的是:url_route_must 对命令行(CLI)请求无效,所以 php think hello 这类指令不会受影响,但 Web 请求全部受控。别在 CLI 场景下测试这个配置。


















