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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章