本篇文章給大家帶來的內容是關于laravel中HTTP內核的詳細解析,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。
Http Kernel
http kernel是laravel中用來串聯框架的各個核心組件來網絡請求的,簡單的說只要是通過public/index.php來啟動框架的都會用到http kernel,而另外的類似通過artisan命令、計劃任務、隊列啟動框架進行處理的都會用到console kernel, 今天我們先梳理一下http kernel做的事情。
內核綁定
既然Http Kernel是Laravel中用來串聯框架的各個部分處理網絡請求的,我們來看一下內核是怎么加載到Laravel中應用實例中來的,在public/index.php中我們就會看見首先就會通過bootstrap/app.php這個腳手架文件來初始化應用程序:
下面是?bootstrap/app.php?的代碼,包含兩個主要部分創建應用實例和綁定內核至 APP 服務容器
<?php // 第一部分: 創建應用實例 $app = new IlluminateFoundationApplication( realpath(__DIR__.'/../') ); // 第二部分: 完成內核綁定 $app->singleton( IlluminateContractsHttpKernel::class, AppHttpKernel::class ); $app->singleton( IlluminateContractsConsoleKernel::class, AppConsoleKernel::class ); $app->singleton( IlluminateContractsDebugExceptionHandler::class, AppExceptionsHandler::class ); return $app;
HTTP 內核繼承自 IlluminateFoundationHttpKernel類,在 HTTP 內核中 內它定義了中間件相關數組, 中間件提供了一種方便的機制來過濾進入應用的 HTTP 請求和加工流出應用的HTTP響應。
<?php namespace AppHttp; use IlluminateFoundationHttpKernel as HttpKernel; class Kernel extends HttpKernel { /** * The application's global HTTP middleware stack. * * These middleware are run during every request to your application. * * @var array */ protected $middleware = [ IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class, IlluminateFoundationHttpMiddlewareValidatePostSize::class, AppHttpMiddlewareTrimStrings::class, IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class, AppHttpMiddlewareTrustProxies::class, ]; /** * The application's route middleware groups. * * @var array */ protected $middlewareGroups = [ 'web' => [ AppHttpMiddlewareEncryptCookies::class, IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class, IlluminateSessionMiddlewareStartSession::class, // IlluminateSessionMiddlewareAuthenticateSession::class, IlluminateViewMiddlewareShareErrorsFromSession::class, AppHttpMiddlewareVerifyCsrfToken::class, IlluminateRoutingMiddlewareSubstituteBindings::class, ], 'api' => [ 'throttle:60,1', 'bindings', ], ]; /** * The application's route middleware. * * These middleware may be assigned to groups or used inpidually. * * @var array */ protected $routeMiddleware = [ 'auth' => IlluminateAuthMiddlewareAuthenticate::class, 'auth.basic' => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class, 'bindings' => IlluminateRoutingMiddlewareSubstituteBindings::class, 'can' => IlluminateAuthMiddlewareAuthorize::class, 'guest' => AppHttpMiddlewareRedirectIfAuthenticated::class, 'throttle' => IlluminateRoutingMiddlewareThrottleRequests::class, ]; }
在其父類 「IlluminateFoundationHttpKernel」 內部定義了屬性名為 「bootstrappers」 的 引導程序 數組:
protected $bootstrappers = [ IlluminateFoundationBootstrapLoadEnvironmentVariables::class, IlluminateFoundationBootstrapLoadConfiguration::class, IlluminateFoundationBootstrapHandleExceptions::class, IlluminateFoundationBootstrapRegisterFacades::class, IlluminateFoundationBootstrapRegisterProviders::class, IlluminateFoundationBootstrapBootProviders::class, ];
引導程序組中 包括完成環境檢測、配置加載、異常處理、Facades 注冊、服務提供者注冊、啟動服務這六個引導程序。
應用解析內核
在將應用初始化階段將Http內核綁定至應用的服務容器后,緊接著在public/index.php中我們可以看到使用了服務容器的make方法將Http內核實例解析了出來:
$kernel = $app->make(IlluminateContractsHttpKernel::class);
在實例化內核時,將在 HTTP 內核中定義的中間件注冊到了 路由器,注冊完后就可以在實際處理 HTTP 請求前調用路由上應用的中間件實現過濾請求的目的:
namespace IlluminateFoundationHttp; ... class Kernel implements KernelContract { /** * Create a new HTTP kernel instance. * * @param IlluminateContractsFoundationApplication $app * @param IlluminateRoutingRouter $router * @return void */ public function __construct(Application $app, Router $router) { $this->app = $app; $this->router = $router; $router->middlewarePriority = $this->middlewarePriority; foreach ($this->middlewareGroups as $key => $middleware) { $router->middlewareGroup($key, $middleware); } foreach ($this->routeMiddleware as $key => $middleware) { $router->aliasMiddleware($key, $middleware); } } } namespace Illuminate/Routing; class Router implements RegistrarContract, BindingRegistrar { /** * Register a group of middleware. * * @param string $name * @param array $middleware * @return $this */ public function middlewareGroup($name, array $middleware) { $this->middlewareGroups[$name] = $middleware; return $this; } /** * Register a short-hand name for a middleware. * * @param string $name * @param string $class * @return $this */ public function aliasMiddleware($name, $class) { $this->middleware[$name] = $class; return $this; } }
處理HTTP請求
通過服務解析完成Http內核實例的創建后就可以用HTTP內核實例來處理HTTP請求了
//public/index.php $response = $kernel->handle( $request = IlluminateHttpRequest::capture() );
在處理請求之前會先通過IlluminateHttpRequest的?capture()?方法以進入應用的HTTP請求的信息為基礎創建出一個 Laravel Request請求實例,在后續應用剩余的生命周期中Request請求實例就是對本次HTTP請求的抽象
將HTTP請求抽象成Laravel Request請求實例后,請求實例會被傳導進入到HTTP內核的handle方法內部,請求的處理就是由handle方法來完成的。
namespace IlluminateFoundationHttp; class Kernel implements KernelContract { /** * Handle an incoming HTTP request. * * @param IlluminateHttpRequest $request * @return IlluminateHttpResponse */ 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 EventsRequestHandled($request, $response) ); return $response; } }
handle?方法接收一個請求對象,并最終生成一個響應對象。其實handle方法我們已經很熟悉了在講解很多模塊的時候都是以它為出發點逐步深入到模塊的內部去講解模塊內的邏輯的,其中sendRequestThroughRouter方法在服務提供者和中間件都提到過,它會加載在內核中定義的引導程序來引導啟動應用然后會將使用Pipeline對象傳輸HTTP請求對象流經框架中定義的HTTP中間件們和路由中間件們來完成過濾請求最終將請求傳遞給處理程序(控制器方法或者路由中的閉包)由處理程序返回相應的響應。
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()); } /*引導啟動Laravel應用程序 1. DetectEnvironment 檢查環境 2. LoadConfiguration 加載應用配置 3. ConfigureLogging 配置日至 4. HandleException 注冊異常處理的Handler 5. RegisterFacades 注冊Facades 6. RegisterProviders 注冊Providers 7. BootProviders 啟動Providers */ public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { /**依次執行$bootstrappers中每一個bootstrapper的bootstrap()函數 $bootstrappers = [ 'IlluminateFoundationBootstrapDetectEnvironment', 'IlluminateFoundationBootstrapLoadConfiguration', 'IlluminateFoundationBootstrapConfigureLogging', 'IlluminateFoundationBootstrapHandleExceptions', 'IlluminateFoundationBootstrapRegisterFacades', 'IlluminateFoundationBootstrapRegisterProviders', 'IlluminateFoundationBootstrapBootProviders', ];*/ $this->app->bootstrapWith($this->bootstrappers()); } }
發送響應
經過上面的幾個階段后我們最終拿到了要返回的響應,接下來就是發送響應了。
//public/index.php $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); // 發送響應 $response->send();
發送響應由 IlluminateHttpResponse的send()方法完成父類其定義在父類SymfonyComponentHttpFoundationResponse中。
public function send() { $this->sendHeaders();// 發送響應頭部信息 $this->sendContent();// 發送報文主題 if (function_exists('fastcgi_finish_request')) { fastcgi_finish_request(); } elseif (!in_array(PHP_SAPI, array('cli', 'phpdbg'), true)) { static::closeOutputBuffers(0, true); } return $this; }
關于Response對象的詳細分析可以參看我們之前講解Laravel Response對象的章節。
終止應用程序
響應發送后,HTTP內核會調用terminable中間件做一些后續的處理工作。比如,Laravel 內置的「session」中間件會在響應發送到瀏覽器之后將會話數據寫入存儲器中。
// public/index.php // 終止程序 $kernel->terminate($request, $response);
//IlluminateFoundationHttpKernel public function terminate($request, $response) { $this->terminateMiddleware($request, $response); $this->app->terminate(); } // 終止中間件 protected function terminateMiddleware($request, $response) { $middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge( $this->gatherRouteMiddleware($request), $this->middleware ); foreach ($middlewares as $middleware) { if (! is_string($middleware)) { continue; } list($name, $parameters) = $this->parseMiddleware($middleware); $instance = $this->app->make($name); if (method_exists($instance, 'terminate')) { $instance->terminate($request, $response); } } }
Http內核的terminate方法會調用teminable中間件的terminate方法,調用完成后從HTTP請求進來到返回響應整個應用程序的生命周期就結束了。
總結
本節介紹的HTTP內核起到的主要是串聯作用,其中設計到的初始化應用、引導應用、將HTTP請求抽象成Request對象、傳遞Request對象通過中間件到達處理程序生成響應以及響應發送給客戶端。