一、概述
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);