要将请求更深入地传递到应用程序(允许中间件“传递”),只需使用 $request 调用 $next 回调。
https://laravel.com/docs/5.4/middleware#defining-middleware
当 Laravel 处理请求时,它会运行堆栈中所有适用的中间件。中间件可以设置为在路由/控制器方法之前和/或之后运行。
为了能够做到这一点,Laravel 使用了Illuminate\Pipeline\Pipeline。本质上,它使用array_reduce 遍历中间件堆栈,然后返回一个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);
});
};);
};);
};
希望这会有所帮助!