如何在另一个中间件中使用 'Clousre $next' 调用 Laravel 中间件的 handle() 方法?
How handle() method of Laravel middleware is called using 'Clousre $next' in another Middleware?
这是来自 Laravel 的 ValidatePostSize:
的 handle() 方法
public function handle($request, Closure $next)
{
$max = $this->getPostMaxSize();
if ($max > 0 && $request->server('CONTENT_LENGTH') > $max) {
throw new PostTooLargeException;
}
return $next($request);
}
现在,使用 $next($request) 为另一个中间件调用此方法。我的理解是 handle() 方法被转换为 $next。我想知道这是如何发生的。
接下来是一个Closure,一个匿名函数的变量。在您的代码中,您有 return $next($request);
。 $next 是一个闭包,基于您的第二个方法参数。这意味着您的方法的 return 值是匿名函数 return.
例如:
// this is the Closure.
$next = function ($parameter) {
return $parameter . ' This message is modified by $next';
};
public function handle($message, Closure $next)
{
return $next($message);
}
// test the output
$message = 'Hello World!';
echo handle($message, $next); // output will be 'Hello World! This message is modified by $next'
To pass the request deeper into the application (allowing the middleware to "pass"), simply call the $next callback with the $request.
https://laravel.com/docs/5.4/middleware#defining-middleware
当 Laravel 正在处理一个请求时,它 运行 调用堆栈中的所有适用中间件。在route/controller方法之后and/or之前可以设置中间件运行
要做到这一点 Laravel 使用 Illuminate\Pipeline\Pipeline
。本质上,它使用 array_reduce
遍历中间件堆栈,然后 returns 和 Closure
来执行该中间件。这样做的美妙之处在于使用 array_reverse
允许将下一个中间件执行传递给前一个。
再详细一点:
当调用 Illuminate\Foundation\Http\Kernel@handle
时,它会用 sendRequestThroughRouter
构建响应,其中包含以下内容:
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
Pipeline
是 Illuminate\Routing\Pipeline
扩展 Illuminate\Pipeline\Pipeline
。
上面的then()
方法本质上是:
->then(function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
})
然后意味着我们从一个接受最终结果的闭包开始(请记住此时不会调用闭包)。
然后,在then()
方法中,出现上面提到的array_reduce
和array_reverse
部分。
这里是 then()
方法中实际发生时间的简化示例(假定您知道 array_reduce
的工作原理):
function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->middlewares),
//Remember $nextClosure is going to be the closure returned
//from the previous iteration
function ($nextClosure, $middlewareClass) {
//This is the $next closure you see in your middleware
return function ($request) use ($nextClosure, $middlewareClass) {
//Resolve the middleware
$middleware = app($middlewareClass);
//Call the middleware
return $middleware->{$this->method}($request, $nextClosure);
};
},
//The finial closure that will be called that resolves the destination
function ($request) use ($destination) {
return $destination($request);
}
);
return $pipeline($this->request);
}
假设我们有 3 个中间件:
[
One::class,
Two::class,
Three::class,
];
上面的 $pipeline
变量基本上是:
function ($request) {
return app(One::class)->handle($request, function ($request) {
return app(Two::class)->handle($request, function ($request) {
return app(Three::class)->handle($request, function ($request) {
return $destination($request);
});
};);
};);
};
希望对您有所帮助!
这是来自 Laravel 的 ValidatePostSize:
的 handle() 方法public function handle($request, Closure $next)
{
$max = $this->getPostMaxSize();
if ($max > 0 && $request->server('CONTENT_LENGTH') > $max) {
throw new PostTooLargeException;
}
return $next($request);
}
现在,使用 $next($request) 为另一个中间件调用此方法。我的理解是 handle() 方法被转换为 $next。我想知道这是如何发生的。
接下来是一个Closure,一个匿名函数的变量。在您的代码中,您有 return $next($request);
。 $next 是一个闭包,基于您的第二个方法参数。这意味着您的方法的 return 值是匿名函数 return.
例如:
// this is the Closure.
$next = function ($parameter) {
return $parameter . ' This message is modified by $next';
};
public function handle($message, Closure $next)
{
return $next($message);
}
// test the output
$message = 'Hello World!';
echo handle($message, $next); // output will be 'Hello World! This message is modified by $next'
To pass the request deeper into the application (allowing the middleware to "pass"), simply call the $next callback with the $request. https://laravel.com/docs/5.4/middleware#defining-middleware
当 Laravel 正在处理一个请求时,它 运行 调用堆栈中的所有适用中间件。在route/controller方法之后and/or之前可以设置中间件运行
要做到这一点 Laravel 使用 Illuminate\Pipeline\Pipeline
。本质上,它使用 array_reduce
遍历中间件堆栈,然后 returns 和 Closure
来执行该中间件。这样做的美妙之处在于使用 array_reverse
允许将下一个中间件执行传递给前一个。
再详细一点:
当调用 Illuminate\Foundation\Http\Kernel@handle
时,它会用 sendRequestThroughRouter
构建响应,其中包含以下内容:
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
Pipeline
是 Illuminate\Routing\Pipeline
扩展 Illuminate\Pipeline\Pipeline
。
上面的then()
方法本质上是:
->then(function ($request) {
$this->app->instance('request', $request);
return $this->router->dispatch($request);
})
然后意味着我们从一个接受最终结果的闭包开始(请记住此时不会调用闭包)。
然后,在then()
方法中,出现上面提到的array_reduce
和array_reverse
部分。
这里是 then()
方法中实际发生时间的简化示例(假定您知道 array_reduce
的工作原理):
function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->middlewares),
//Remember $nextClosure is going to be the closure returned
//from the previous iteration
function ($nextClosure, $middlewareClass) {
//This is the $next closure you see in your middleware
return function ($request) use ($nextClosure, $middlewareClass) {
//Resolve the middleware
$middleware = app($middlewareClass);
//Call the middleware
return $middleware->{$this->method}($request, $nextClosure);
};
},
//The finial closure that will be called that resolves the destination
function ($request) use ($destination) {
return $destination($request);
}
);
return $pipeline($this->request);
}
假设我们有 3 个中间件:
[
One::class,
Two::class,
Three::class,
];
上面的 $pipeline
变量基本上是:
function ($request) {
return app(One::class)->handle($request, function ($request) {
return app(Two::class)->handle($request, function ($request) {
return app(Three::class)->handle($request, function ($request) {
return $destination($request);
});
};);
};);
};
希望对您有所帮助!