Laravel 请求类 Reques-响应类 Response-中间件底层源码剖析
学习链接
xueyuanjun.com/post/9818
xueyuanjun.com/post/9820
Laravel 请求类 Request 剖析
- 捕获用户请求
- 获取请求对象
- 访问用户当前请求数据
- 访问持久化请求数据
注:所谓持久化的用户请求数据通常指的是用户上次请求输入的数据及用户 Cookie 数据。
响应类 Response 剖析
和 Laravel 请求对象类 Request 类似,代码底层有一个 Response 类用于表示发送给终端用户的应用响应,其中包含响应头、Cookie、响应内容、以及其它发送给终端用户浏览器用于渲染响应页面的东西。
Laravel 响应的底层实现
Symfony\Component\HttpFoundation\Response 基类
Symfony 实现了对状态码、HTTP协议版本、缓存、Etag、字符编码、响应实体等响应信息的封装
在 Illuminate\Http\Response 中,对 JSON 格式响应做了特别的优化
在 Laravel 请求的生命周期中,用户请求经过匹配路由处理后(通过控制器或匿名函数),就会返回相应的响应实例
响应头和响应内容的设置是在具体路由定义中实现
兜底处理,由路由器类 Illuminate\Routing\Router 的 toResponse 方法进行(自定义响应类的处理、返回的是数组、字符串、视图等非 Response 实例的处理)
请求处理完成,响应实例准备停当,发送给终端用户了,这段逻辑位于入口文件 public/index.php 中
以上,就是响应类 Response 实例化及返回给用户的底层实现原理
中间件底层原理
- 从 vendor/laravel/framework/src/Illuminate/Foundation/Http/Kernel.php 的 handle 方法开始
- 中间件的执行逻辑则是从该方法中的 sendRequestThroughRouter 开始
protected function sendRequestThroughRouter($request)
{
$this->app->instance('request', $request);
Facade::clearResolvedInstance('request');
$this->bootstrap();
return (new Pipeline($this->app))
->send($request)
->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
->then($this->dispatchToRouter());
}
构造
Illuminate\Routing\Pipeline
实例。然后将当前请求实例
$request
赋值到Pipeline
的$passable
属性。如果应用启用中间件功能的话(默认启用),则将全局中间件数组
$middleware
赋值到Pipeline
的$pipes
属性接下来调用
dispatchToRouter
方法将请求转发给路由,该方法返回一个闭包函数,这个闭包函数将在处理完全局中间件逻辑后执行接下来调用
Pipeline
的then
方法:这里首先调用
array_reduce
函数进行预处理,函数意思发送数组中的值到用户自定义函数,并返回一个字符串,类似于循环调用自定义函数。遍历完所有全局中间件数组后,由于 carry 函数返回的还是闭包函数,所以直到此时都还没有执行任何中间件的 handle 方法,这段处理的意义是将所有全局中间件和路由处理通过统一的闭包函数进行迭代调用。最终返回的 $pipeline 是一个闭包函数
当执行完最后一个全局中间件 \App\Http\Middleware\TrustProxies::class,且请求未中断,控制流程进入到执行 $this->prepareDestination($destination) 返回的闭包函数,其中包含了应用到路由的中间件处理逻辑
最后,除了请求处理前执行的中间件,还有请求处理后执行的「终端中间件」,这些中间件在会在响应发送到客户端之后执行
中间件的实现实际上应用了管道设计模式,你可以参考这篇教程对其进行了解。