必须同时设置'url_route_must'=>true、'url_controller_layer'=>''、'url_action_layer'=>''三项配置,并添加兜底路由Route::any('*', fn()=>abort(404)),才能彻底阻断非绑定域名对默认模块的访问。

直接关闭默认模块的自动访问能力,不是靠“不写模块名”来绕开,而是从路由强制性和入口调度两层堵死。否则 ?c=Index&a=index 或 /index/index 这类请求依然能穿透进来。
为什么域名绑定后还能访问默认模块
ThinkPHP5 的域名绑定(Route::domain())只是把某域名映射到指定模块/控制器,并不自动禁用其他访问方式。框架底层仍保留默认的 PATH_INFO 解析和 c/a 参数调度逻辑,只要没显式关掉,就始终存在直连入口。
-
url_route_must = false:路由不强制,未匹配路由时自动 fallback 到默认模块 -
url_controller_layer和url_action_layer未清空:?c=xxx&a=yyy仍可绕过所有路由规则 - 没加兜底路由:哪怕绑定了
blog.thinkphp.cn,www.thinkphp.cn仍走默认模块
必须关闭的三个配置项
仅靠 Route::domain() 绑定无法实现“只允许特定域名访问”,得配合框架级开关切断默认通路:
- 在
application/config.php中设'url_route_must' => true:所有请求必须命中某条路由规则,否则 404 - 同文件中设
'url_controller_layer' => '':禁用c参数解析 - 同文件中设
'url_action_layer' => '':禁用a参数解析
这三项缺一不可。只开 url_route_must 而不清空 url_controller_layer,?c=Index 仍能直达控制器。
兜底路由必须写在 route/app.php 底部
即使开了 url_route_must,也要防止漏配——比如忘了给主域名写路由,它就会 404,但你可能希望它也走某个模块。更稳妥的做法是显式拦截非绑定域名:
Route::domain('blog', 'blog');
Route::domain('admin.thinkphp.cn', 'admin');
// 其他所有域名、IP、无域名请求全部拒绝
Route::any('*', function () {
return abort(404);
});
注意:Route::any('*', ...) 必须放在所有 Route::domain() 之后,否则会提前截断域名路由注册。
入口文件不能依赖默认调度机制
如果你用了多入口(如 admin.php),别在其中写 define('BIND_MODULE', 'admin') 就完事。这种绑定只影响 URL 解析,不关闭 c/a 解析。正确做法是:
- 在
admin.php中调用\think\App::route(false)关闭该入口的路由系统(避免冲突) - 但前提是这个入口本身已通过
url_route_must = true和参数层清空做过全局约束 - 否则,
admin.php?c=Index依然能绕过绑定,直连非 admin 模块
真正干净的隔离,是让非绑定域名连入口都进不来,而不是进了再拦。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











