面试问你Laravel 底层是如何处理HTTP请求,你可以这么回答

一、概述

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

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

二、剖析

逐行分析 index.php 的代码。

1、引入自动加载

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

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

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

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

<?php
// 创建一个 Application 实例
$app = new Illuminate\Foundation\Application(
    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);

// 绑定处理HTTP请求的接口实现 到服务容器
$app->singleton(
    Illuminate\Contracts\Http\Kernel::class,
    App\Http\Kernel::class
);

// 绑定处理CLI请求的接口实现 到服务容器
$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    App\Console\Kernel::class
);

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    App\Exceptions\Handler::class
);

// 返回应用程序实例
return $app;

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

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

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


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

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

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

/**
 * 处理传入的http请求,获取一个 Request,返回一个 Response
 * 输入http请求,返回http响应
 *
 * Handle an incoming HTTP request.
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function handle($request)
{
    try {
        $request->enableHttpMethodParameterOverride();
        $response = $this->sendRequestThroughRouter($request);
    } catch (Exception $e) {
        $this->reportException($e);
        $response = $this->renderException($request, $e);
    } catch (Throwable $e) {
        $this->reportException($e = new FatalThrowableError($e));
        $response = $this->renderException($request, $e);
    }
    $this->app['events']->dispatch(
        new RequestHandled($request, $response)
    );
    return $response;
}

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

protected function sendRequestThroughRouter($request)
{
    $this->app->instance('request', $request);
    Facade::clearResolvedInstance('request');

    // 在发送请求到路由之前,先调用 bootstrap() 方法运用应用的启动类
    $this->bootstrap();

    /**
    * 以管道模式来处理 HTTP 请求
    *
    * 全局中间件都校验通过才会将请求分发到路由器进行处理
    * 路由器会将请求 URL 路径与应用注册的所有路由进行匹配,如果有匹配的路由,则先收集该路由所分配的所有路由中间件
    * 通过这些路由中间件对请求进行过滤,所有路由中间件校验通过才会运行对应的匿名函数或控制器方法,执行相应的请求处理逻辑
    * 最后准备好待发送给客户端的响应。
    */
    return (new Pipeline($this->app))
            ->send($request)
            ->through($this->app->shouldSkipMiddleware() ? [] : $this->middleware)
            ->then($this->dispatchToRouter());
}


5、发送响应

$response->send();


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

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



文章来自:www.haveyb.com/article/166
学习与交流:Laravel技术交流微信群

本作品采用《CC 协议》,转载必须注明作者和本文链接
程序员的福利:免费获取 JetBrains 全家桶激活码 推荐:【点击这里获取 。。。激活码适用:AppCode, CLion, DataGrip, DataSpell, dotCover, dotMemory, dotTrace, goland, IntelliJ IDEA Ultimate, phpstorm, pycharm, ReSharper
Laravel00
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
资深程序猿 @ XX科技
文章
62
粉丝
37
喜欢
249
收藏
573
排名:282
访问:3.3 万
私信
所有博文
社区赞助商