中间件 handle() 方法中 $request 参数直接可用,无需 use 或 new;$request->domain() 返回 Host 头而非路由绑定域名,需在路由解析后通过 $request->routeInfo()['domain'] 获取;CLI 环境下部分方法返回空或默认值,须用 $request->isCli() 判断。

中间件 handle() 方法里怎么拿到 $request
ThinkPHP 中间件的 handle() 方法第一个参数就是 $request,无需额外获取或注入。框架在调用中间件时自动传入已初始化的 think\Request 实例。
- 该实例是容器单例,和控制器中注入的
Request是同一个对象 - 不需要
use think\Request后再new Request(),手动 new 会破坏请求数据一致性 - 也不推荐用
think\facade\Request::instance()或request()助手函数,它们可能返回新实例或触发重复解析
示例写法:
public function handle($request, \Closure $next)
{
// 直接使用 $request
$id = $request->param('id');
$isAjax = $request->isAjax();
return $next($request);
}为什么 $request->domain() 拿不到绑定域名
$request->domain() 返回的是原始 HTTP Host 头解析结果(如 admin.example.com),不是路由配置里 bind 的绑定域名。
- 域名绑定(
route_domain或Route::domain())是路由调度阶段才生效的逻辑 - 中间件执行时,路由还没跑完,
$request->routeInfo()里还没有domain或<strong>domain</strong>键 - 如果你在全局中间件(
app/middleware.php)里调用$request->domain(),它永远只反映 Host 头,和多应用配置无关
要安全拿到绑定域名,必须满足两个条件:
立即学习“PHP免费学习笔记(深入)”;
- 中间件注册顺序在
think\middleware\ParseUrl之后(即路由解析已完成) - 使用
$request->routeInfo()['domain'] ?? $request->routeInfo()['<strong>domain</strong>'] ?? null
中间件里修改 $request 属性是否生效
可以往 $request 对象动态加属性(比如 $request->user_id = 123;),但要注意:
- 这些属性不会自动透传到后续控制器方法的参数注入中(控制器里
function index(Request $request)拿到的是原始实例,属性存在但需手动读) - 更稳妥的做法是把数据挂到
$request->with('key', $value)(TP8 支持)或通过$request->attr('key', $value)(TP6+) - 若需跨中间件传递状态,建议用
$request->setAttr()+$request->getAttr(),避免直接赋值导致不可预期行为
CLI 环境下中间件的 $request 有什么不同
CLI 请求没有 HTTP 头、没有 Host、没有 Cookie,$request 仍会被创建,但部分方法返回空或默认值:
-
$request->domain()、$request->host()、$request->url()返回空字符串 -
$request->param()只能取命令行参数(php think hello --name=foo→$request->param('name')='foo') -
$request->post()、$request->file()始终为空数组 - 判断请求类型(
$request->isGet()等)全部返回false,需改用$request->isCli()
真正容易被忽略的是:中间件里的 $request 行为完全取决于当前运行环境,而不是你写的代码本身。调试时务必确认是 HTTP 还是 CLI 上下文。



















