保护私人版权,尊重他人版权。转载请注明出处并附带页面链接
1.中间件 类型
lumen 中的中间件份为两种
- 全局中间件
1
2
3$app->middleware([
App\Http\Middleware\ExampleMiddleware::class
]); - 路由中间件
1
2
3$app->routeMiddleware([
'auth'=> App\Http\Middleware\Authenticate::class
]);
2.请求过程
请求都从入口文件进去 (public/index.php)
1
2$app = require __DIR__.'/../bootstrap/app.php';
$app->run();run方法是 vendor/laravel/lumen-framework/src/Application.php这个类中使用到的trait,trait为Concerns\RoutesRequests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Application extends Container
{
use Concerns\RoutesRequests,
Concerns\RegistersExceptionHandlers;
public function run($request = null)
{
$response = $this->dispatch($request); // 处理请求 (中间件 等)
if ($response instanceof SymfonyResponse) {
$response->send(); // 返回 http 请求结果
} else {
echo (string) $response;
}
// 处理 middleware 中的 terminate() -->终止中间件 (有时候中间件可能需要在 HTTP 响应发送到浏览器之后做一些工作)
if (count($this->middleware) > 0) {
$this->callTerminableMiddleware($response);
}
}
}在bootstrap/app.php中我们进行了中间件的注册,这里的注册就是将中间件写入到Application类引用的trait RoutesRequests的两个属性当中
1
2
3
4
5trait RoutesRequests
{
protected $middleware = [];
protected $routeMiddleware = [];
}$this->dispatch($request)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26trait RoutesRequests
{
public function dispatch($request = null)
{
// 初始化 $request
list($method, $pathInfo) = $this->parseIncomingRequest($request);
try {
// pipeline 处理 全局 中间件
return $this->sendThroughPipeline($this->middleware, function () use ($method, $pathInfo) {
if (isset($this->router->getRoutes()[$method.$pathInfo])) {
// handleFoundRoute() 处理 route中间件
return $this->handleFoundRoute([true, $this->router->getRoutes()[$method.$pathInfo]['action'], []]);
}
// 处理 没有 路由到的 请求404
return $this->handleDispatcherResponse(
$this->createDispatcher()->dispatch($method, $pathInfo)
);
});
} catch (Exception $e) {
return $this->prepareResponse($this->sendExceptionToHandler($e));
} catch (Throwable $e) {
return $this->prepareResponse($this->sendExceptionToHandler($e));
}
}
}$this->sendThroughPipeline,这里用到了Pipeline,是是实现中间件的关键所在
1
2
3
4
5
6
7
8
9
10
11
12
13
14trait RoutesRequests
{
protected function sendThroughPipeline(array $middleware, Closure $then)
{
if (count($middleware) > 0 && ! $this->shouldSkipMiddleware()) {
// pipeline 实现中间件
return (new Pipeline($this))
->send($this->make('request')) // 设置通过管道的对象
->through($middleware) //设置管道 即定义的中间件
->then($then); //让管道对象通过中间件,也就是执行闭包 $then为初始化的闭包函数
}
return $then();
}
}
3.Pipeline原理实现
1 | class Pipeline |
这里使用到了array_reduce来迭代数组,最后返回的是一个闭包函数调用栈,然后通过 $pipeline($this->passable)执行这个闭包函数栈。我们看到array_reduce方法的第一个参数,将中间件进行了array_reverse数组反转,这样的话最后一个中间件是最早进入匿名函数调用栈,因此在执行过程它才会是最后一个被执行。整个实现其实使用到了一个设计模式叫做装饰器模式。
这里我写了一个简单的pipeline使用例子
1 | $add = function ($result, $closure) { |
上面代码中我们可以看到,我定义了一个将对象+1的匿名函数和一个将对象乘10的匿名,对象定义为数字10依次通过两个函数,最后得到结果 (10+1)*10 =110 返回。
4.tips
array_reduce解释
array_reduce它是专门用来迭代数组的。该函数最多接收三个参数。
第一个参数接收数组
第二个参数函数名,也可以是匿名函数,函数有两个参数,分别代表$result和$item
第三个参数(可选),该参数将被当成是数组中的第一个值来处理,或者如果数组为空的话就作为最终返回值