摘要:終止程序終止中間件內(nèi)核的方法會調(diào)用中間件的方法,調(diào)用完成后從請求進來到返回響應(yīng)整個應(yīng)用程序的生命周期就結(jié)束了。
Http Kernel
Http Kernel是Laravel中用來串聯(lián)框架的各個核心組件來網(wǎng)絡(luò)請求的,簡單的說只要是通過public/index.php來啟動框架的都會用到Http Kernel,而另外的類似通過artisan命令、計劃任務(wù)、隊列啟動框架進行處理的都會用到Console Kernel, 今天我們先梳理一下Http Kernel做的事情。
內(nèi)核綁定既然Http Kernel是Laravel中用來串聯(lián)框架的各個部分處理網(wǎng)絡(luò)請求的,我們來看一下內(nèi)核是怎么加載到Laravel中應(yīng)用實例中來的,在public/index.php中我們就會看見首先就會通過bootstrap/app.php這個腳手架文件來初始化應(yīng)用程序:
下面是 bootstrap/app.php 的代碼,包含兩個主要部分創(chuàng)建應(yīng)用實例和綁定內(nèi)核至 APP 服務(wù)容器
singleton( IlluminateContractsHttpKernel::class, AppHttpKernel::class ); $app->singleton( IlluminateContractsConsoleKernel::class, AppConsoleKernel::class ); $app->singleton( IlluminateContractsDebugExceptionHandler::class, AppExceptionsHandler::class ); return $app;
HTTP 內(nèi)核繼承自 IlluminateFoundationHttpKernel類,在 HTTP 內(nèi)核中 內(nèi)它定義了中間件相關(guān)數(shù)組, 中間件提供了一種方便的機制來過濾進入應(yīng)用的 HTTP 請求和加工流出應(yīng)用的HTTP響應(yīng)。
[ 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 individually. * * @var array */ protected $routeMiddleware = [ "auth" => IlluminateAuthMiddlewareAuthenticate::class, "auth.basic" => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class, "bindings" => IlluminateRoutingMiddlewareSubstituteBindings::class, "can" => IlluminateAuthMiddlewareAuthorize::class, "guest" => AppHttpMiddlewareRedirectIfAuthenticated::class, "throttle" => IlluminateRoutingMiddlewareThrottleRequests::class, ]; }
在其父類 「IlluminateFoundationHttpKernel」 內(nèi)部定義了屬性名為 「bootstrappers」 的 引導(dǎo)程序 數(shù)組:
protected $bootstrappers = [ IlluminateFoundationBootstrapLoadEnvironmentVariables::class, IlluminateFoundationBootstrapLoadConfiguration::class, IlluminateFoundationBootstrapHandleExceptions::class, IlluminateFoundationBootstrapRegisterFacades::class, IlluminateFoundationBootstrapRegisterProviders::class, IlluminateFoundationBootstrapBootProviders::class, ];
引導(dǎo)程序組中 包括完成環(huán)境檢測、配置加載、異常處理、Facades 注冊、服務(wù)提供者注冊、啟動服務(wù)這六個引導(dǎo)程序。
有關(guān)中間件和引導(dǎo)程序相關(guān)內(nèi)容的講解可以瀏覽我們之前相關(guān)章節(jié)的內(nèi)容。
應(yīng)用解析內(nèi)核在將應(yīng)用初始化階段將Http內(nèi)核綁定至應(yīng)用的服務(wù)容器后,緊接著在public/index.php中我們可以看到使用了服務(wù)容器的make方法將Http內(nèi)核實例解析了出來:
$kernel = $app->make(IlluminateContractsHttpKernel::class);
在實例化內(nèi)核時,將在 HTTP 內(nèi)核中定義的中間件注冊到了 路由器,注冊完后就可以在實際處理 HTTP 請求前調(diào)用路由上應(yīng)用的中間件實現(xiàn)過濾請求的目的:
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請求
通過服務(wù)解析完成Http內(nèi)核實例的創(chuàng)建后就可以用HTTP內(nèi)核實例來處理HTTP請求了
//public/index.php $response = $kernel->handle( $request = IlluminateHttpRequest::capture() );
在處理請求之前會先通過IlluminateHttpRequest的 capture() 方法以進入應(yīng)用的HTTP請求的信息為基礎(chǔ)創(chuàng)建出一個 Laravel Request請求實例,在后續(xù)應(yīng)用剩余的生命周期中Request請求實例就是對本次HTTP請求的抽象,關(guān)于Laravel Request請求實例的講解可以參考以前的章節(jié)。
將HTTP請求抽象成Laravel Request請求實例后,請求實例會被傳導(dǎo)進入到HTTP內(nèi)核的handle方法內(nèi)部,請求的處理就是由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 方法接收一個請求對象,并最終生成一個響應(yīng)對象。其實handle方法我們已經(jīng)很熟悉了在講解很多模塊的時候都是以它為出發(fā)點逐步深入到模塊的內(nèi)部去講解模塊內(nèi)的邏輯的,其中sendRequestThroughRouter方法在服務(wù)提供者和中間件都提到過,它會加載在內(nèi)核中定義的引導(dǎo)程序來引導(dǎo)啟動應(yīng)用然后會將使用Pipeline對象傳輸HTTP請求對象流經(jīng)框架中定義的HTTP中間件們和路由中間件們來完成過濾請求最終將請求傳遞給處理程序(控制器方法或者路由中的閉包)由處理程序返回相應(yīng)的響應(yīng)。關(guān)于handle方法的注解我直接引用以前章節(jié)的講解放在這里,具體更詳細的分析具體是如何引導(dǎo)啟動應(yīng)用以及如何將傳輸流經(jīng)各個中間件并到達處理程序的內(nèi)容請查看服務(wù)提供器、中間件還有路由這三個章節(jié)。
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()); } /*引導(dǎo)啟動Laravel應(yīng)用程序 1. DetectEnvironment 檢查環(huán)境 2. LoadConfiguration 加載應(yīng)用配置 3. ConfigureLogging 配置日至 4. HandleException 注冊異常處理的Handler 5. RegisterFacades 注冊Facades 6. RegisterProviders 注冊Providers 7. BootProviders 啟動Providers */ public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { /**依次執(zhí)行$bootstrappers中每一個bootstrapper的bootstrap()函數(shù) $bootstrappers = [ "IlluminateFoundationBootstrapDetectEnvironment", "IlluminateFoundationBootstrapLoadConfiguration", "IlluminateFoundationBootstrapConfigureLogging", "IlluminateFoundationBootstrapHandleExceptions", "IlluminateFoundationBootstrapRegisterFacades", "IlluminateFoundationBootstrapRegisterProviders", "IlluminateFoundationBootstrapBootProviders", ];*/ $this->app->bootstrapWith($this->bootstrappers()); } }發(fā)送響應(yīng)
經(jīng)過上面的幾個階段后我們最終拿到了要返回的響應(yīng),接下來就是發(fā)送響應(yīng)了。
//public/index.php $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); // 發(fā)送響應(yīng) $response->send();
發(fā)送響應(yīng)由 IlluminateHttpResponse的send()方法完成父類其定義在父類SymfonyComponentHttpFoundationResponse中。
public function send() { $this->sendHeaders();// 發(fā)送響應(yīng)頭部信息 $this->sendContent();// 發(fā)送報文主題 if (function_exists("fastcgi_finish_request")) { fastcgi_finish_request(); } elseif (!in_array(PHP_SAPI, array("cli", "phpdbg"), true)) { static::closeOutputBuffers(0, true); } return $this; }
關(guān)于Response對象的詳細分析可以參看我們之前講解Laravel Response對象的章節(jié)。
終止應(yīng)用程序響應(yīng)發(fā)送后,HTTP內(nèi)核會調(diào)用terminable中間件做一些后續(xù)的處理工作。比如,Laravel 內(nèi)置的「session」中間件會在響應(yīng)發(fā)送到瀏覽器之后將會話數(shù)據(jù)寫入存儲器中。
// 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內(nèi)核的terminate方法會調(diào)用teminable中間件的terminate方法,調(diào)用完成后從HTTP請求進來到返回響應(yīng)整個應(yīng)用程序的生命周期就結(jié)束了。
總結(jié)本節(jié)介紹的HTTP內(nèi)核起到的主要是串聯(lián)作用,其中設(shè)計到的初始化應(yīng)用、引導(dǎo)應(yīng)用、將HTTP請求抽象成Request對象、傳遞Request對象通過中間件到達處理程序生成響應(yīng)以及響應(yīng)發(fā)送給客戶端。這些東西在之前的章節(jié)里都有講過,并沒有什么新的東西,希望通過這篇文章能讓大家把之前文章里講到的每個點串成一條線,這樣對Laravel整體是怎么工作的會有更清晰的概念。
本文已經(jīng)收錄在系列文章Laravel源碼學(xué)習(xí)里。
也歡迎關(guān)注我的公眾號 網(wǎng)管叨bi叨 ,最近正在籌備準(zhǔn)備分享一些日常工作里學(xué)到和總結(jié)的技術(shù)知識,也會分享一些見聞和學(xué)習(xí)英語的方法。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/29622.html
摘要:其中設(shè)置請求是唯一區(qū)別于內(nèi)核的一個引導(dǎo)程序。和命令行腳本的規(guī)范一樣,如果執(zhí)行命令任務(wù)程序成功會返回拋出異常退出則返回。嚴(yán)格遵循了面向?qū)ο蟪绦蛟O(shè)計的原則。 Console內(nèi)核 上一篇文章我們介紹了Laravel的HTTP內(nèi)核,詳細概述了網(wǎng)絡(luò)請求從進入應(yīng)用到應(yīng)用處理完請求返回HTTP響應(yīng)整個生命周期中HTTP內(nèi)核是如何調(diào)動Laravel各個核心組件來完成任務(wù)的。除了處理HTTP請求一個健壯...
摘要:過去一年時間寫了多篇文章來探討了我認為的框架最核心部分的設(shè)計思路代碼實現(xiàn)。為了大家閱讀方便,我把這些源碼學(xué)習(xí)的文章匯總到這里。數(shù)據(jù)庫算法和數(shù)據(jù)結(jié)構(gòu)這些都是編程的內(nèi)功,只有內(nèi)功深厚了才能解決遇到的復(fù)雜問題。 過去一年時間寫了20多篇文章來探討了我認為的Larave框架最核心部分的設(shè)計思路、代碼實現(xiàn)。通過更新文章自己在軟件設(shè)計、文字表達方面都有所提高,在剛開始決定寫Laravel源碼分析地...
摘要:的契約是一組定義框架提供的核心服務(wù)的接口,例如我們在介紹用戶認證的章節(jié)中到的用戶看守器契約和用戶提供器契約以及框架自帶的模型所實現(xiàn)的契約。接口與團隊開發(fā)當(dāng)你的團隊在開發(fā)大型應(yīng)用時,不同的部分有著不同的開發(fā)速度。 Contracts Laravel 的契約是一組定義框架提供的核心服務(wù)的接口, 例如我們在介紹用戶認證的章節(jié)中到的用戶看守器契約IllumninateContractsAuth...
摘要:設(shè)置生成對象后就要執(zhí)行對象的方法了,該方法定義在類中,其主要目的是對進行微調(diào)使其能夠遵從協(xié)議。最后會把完整的響應(yīng)發(fā)送給客戶端。本文已經(jīng)收錄在系列文章源碼學(xué)習(xí)里,歡迎訪問閱讀。 Response 前面兩節(jié)我們分別講了Laravel的控制器和Request對象,在講Request對象的那一節(jié)我們看了Request對象是如何被創(chuàng)建出來的以及它支持的方法都定義在哪里,講控制器時我們詳細地描述了...
摘要:根據(jù)提供的超級全局數(shù)組來創(chuàng)建實例上面的代碼有一處需要額外解釋一下,自開始內(nèi)建的可以通過命令行解釋器來啟動,例如但是內(nèi)建有一個是將和這兩個請求首部存儲到了和中,為了統(tǒng)一內(nèi)建服務(wù)器和真正的中的請求首部字段所以在這里做了特殊處理。 Request 很多框架都會將來自客戶端的請求抽象成類方便應(yīng)用程序使用,在Laravel中也不例外。IlluminateHttpRequest類在Laravel框...
閱讀 2857·2021-09-10 10:51
閱讀 2222·2021-09-02 15:21
閱讀 3214·2019-08-30 15:44
閱讀 882·2019-08-29 18:34
閱讀 1662·2019-08-29 13:15
閱讀 3331·2019-08-26 11:37
閱讀 2706·2019-08-26 10:46
閱讀 1118·2019-08-26 10:26