Laravel 底层如何处理HTTP请求

一、概述

web 服务器对 HTTP 请求的处理流程大体上都是这样的:在某个端口监听请求,请求进入后运行程序,然后将程序运行结果以响应的形式发送出去。

Laravel 框架构建的 Web 应用处理 HTTP 请求的流程亦是如此。所有 HTTP 请求都会被转发到单入口文件 /public/index.php。

 

二、剖析

逐行分析 index.php 的代码。

1、引入自动加载

  1. require __DIR__.'/../vendor/autoload.php';

 
2、创建一个 Application 实例,作为全局的服务容器,并将处理请求的核心类Kernel实现实例 绑定到该容器中。

  1. $app = require_once __DIR__.'/../bootstrap/app.php';

 
注:app.php文件内的处理:

  1. <?php
  2. // 创建一个 Application 实例
  3. $app = new Illuminate\Foundation\Application(
  4. $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
  5. );
  6. // 绑定处理HTTP请求的接口实现 到服务容器
  7. $app->singleton(
  8. Illuminate\Contracts\Http\Kernel::class,
  9. App\Http\Kernel::class
  10. );
  11. // 绑定处理CLI请求的接口实现 到服务容器
  12. $app->singleton(
  13. Illuminate\Contracts\Console\Kernel::class,
  14. App\Console\Kernel::class
  15. );
  16. $app->singleton(
  17. Illuminate\Contracts\Debug\ExceptionHandler::class,
  18. App\Exceptions\Handler::class
  19. );
  20. // 返回应用程序实例
  21. return $app;

 
3、从服务容器中解析处理 HTTP 请求的 Kernel 实例

  1. $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

这里的 make 方法在 Illuminate\Foundation\Application 中,作用就是解析

 
4、处理 HTTP 请求的核心代码

  1. $response = $kernel->handle(
  2. $request = Illuminate\Http\Request::capture()
  3. );

$kernel 是 App\Http\Kernel 的父类,即 Illuminate\Foundation\Http\Kernel,我们进入到 handle() 方法

  1. /**
  2. * 处理传入的http请求,获取一个 Request,返回一个 Response
  3. * 输入http请求,返回http响应
  4. *
  5. * Handle an incoming HTTP request.
  6. * @param \Illuminate\Http\Request $request
  7. * @return \Illuminate\Http\Response
  8. */
  9. public function handle($request)
  10. {
  11. try {
  12. $request->enableHttpMethodParameterOverride();
  13. $response = $this->sendRequestThroughRouter($request);
  14. } catch (Exception $e) {
  15. $this->reportException($e);
  16. $response = $this->renderException($request, $e);
  17. } catch (Throwable $e) {
  18. $this->reportException($e = new FatalThrowableError($e));
  19. $response = $this->renderException($request, $e);
  20. }
  21. $this->app['events']->dispatch(
  22. new RequestHandled($request, $response)
  23. );
  24. return $response;
  25. }

 
我们发现实际进行处理的是 sendRequestThroughRouter() 这个方法

  1. protected function sendRequestThroughRouter($request)
  2. {
  3. $this->app->instance('request', $request);
  4. Facade::clearResolvedInstance('request');
  5. // 在发送请求到路由之前,先调用 bootstrap() 方法运用应用的启动类
  6. $this->bootstrap();
  7. /**
  8. * 以管道模式来处理 HTTP 请求
  9. *
  10. * 全局中间件都校验通过才会将请求分发到路由器进行处理
  11. * 路由器会将请求 URL 路径与应用注册的所有路由进行匹配,如果有匹配的路由,则先收集该路由所分配的所有路由中间件
  12. * 通过这些路由中间件对请求进行过滤,所有路由中间件校验通过才会运行对应的匿名函数或控制器方法,执行相应的请求处理逻辑
  13. * 最后准备好待发送给客户端的响应。
  14. */
  15. return (new Pipeline($this->app))
  16. ->send($request)
  17. ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
  18. ->then($this->dispatchToRouter());
  19. }

 
5、发送响应

  1. $response->send();

 
6、终止程序,做一些善后清理工作(主要包括运行终止中间件,以及注册到服务容器的一些终止回调)

  1. $kernel->terminate($request, $response);

 

 



Top