ThinkPHP6中Request对象不包含路由信息,需通过app('think\route\RuleItem')获取路由规则、名称及参数,且须确保路由已匹配完成。

ThinkPHP 6 的 Request 对象不直接提供路由信息
你用 $request->route() 或 $request->url() 是拿不到当前匹配的路由规则或参数的——Request 只管请求本身(如 query、post、header),路由解析结果由 Route 和调度器完成,不在 Request 实例里。
正确方式:从 think\Route 门面或容器中获取 think\route\RuleItem
路由匹配完成后,框架会把解析出的 RuleItem 实例存到容器里,键为 think\route\RuleItem。在控制器、中间件或闭包中可这样取:
// 在控制器方法中
public function index(\think\Request $request)
{
$ruleItem = app('think\route\RuleItem');
if ($ruleItem) {
$name = $ruleItem->getName(); // 路由名(如 'user.list')
$pattern = $ruleItem->getRule(); // 原始路由定义(如 'user/:id')
$option = $ruleItem->getOption(); // 路由选项(如 ['method' => 'GET'])
$param = $ruleItem->getMatchedParam(); // 匹配出的变量(如 ['id' => '123'])
}
}
- 必须确保路由已成功匹配(比如在路由闭包或控制器中调用,而非全局中间件早期阶段)
-
$ruleItem->getMatchedParam()返回的是经过变量绑定和类型转换后的值,比$request->param()更“原始”且不含默认值 - 若使用了资源路由或分组嵌套,
$ruleItem->getRule()返回的是完整路径(如'admin/user/:id@PUT'),不是注册时写的简写
想在中间件里安全获取?得确认路由已解析完成
很多开发者在全局中间件里调用 app('think\route\RuleItem') 拿到 null,是因为中间件执行顺序早于路由匹配。解决办法:
- 把中间件注册到
app/middleware.php的['http' => [...]]数组末尾,或设为['route' => [...]]类型(TP6.1+ 支持) - 更稳妥的做法:在中间件
handle()中延迟获取,例如$this->app->afterStart(function () { ... });,但注意这会丢失同步上下文 - 或者改用
\think\App::hook('route_end', function ($ruleItem) { ... });监听路由结束事件
$request->path() 和 $request->url() 不是路由信息,别混淆
这两个方法返回的是原始 HTTP 请求路径或完整 URL,和路由定义无关:
立即学习“PHP免费学习笔记(深入)”;
-
$request->path()→'user/123'(不含 query) -
$request->url()→'/user/123?tab=info' - 它们不会因路由重写(如
Route::get('u/:id', 'user/read'))而变化,也不会反映路由别名或分组前缀 - 如果只是想做路径判断(比如菜单高亮),用这些可以;但要取路由名、参数绑定规则、中间件配置等,必须走
RuleItem
真正容易被忽略的是:路由对象生命周期极短,只在本次请求调度链中有效,且不跨子请求(比如 Url::build() 内部另起路由解析,不会复用当前 RuleItem)。需要动态生成链接或权限校验时,别试图缓存它。



















