摘要:年月日階段劃分請(qǐng)求到響應(yīng)的整個(gè)執(zhí)行階段歸納為個(gè)程序啟動(dòng)準(zhǔn)備階段文件自動(dòng)加載服務(wù)容器實(shí)例化基礎(chǔ)服務(wù)提供者的注冊(cè)核心類的實(shí)例化請(qǐng)求實(shí)例化階段實(shí)例化實(shí)例請(qǐng)求處理階段準(zhǔn)備請(qǐng)求處理的環(huán)境將請(qǐng)求實(shí)例通過中間件處理及通過路由和控制器的分發(fā)控制響應(yīng)發(fā)送和
Last-Modified: 2019年5月10日16:19:07
階段劃分Laravel 5.5
請(qǐng)求到響應(yīng)的整個(gè)執(zhí)行階段歸納為 4 個(gè):
程序啟動(dòng)準(zhǔn)備階段
文件自動(dòng)加載
服務(wù)容器實(shí)例化
基礎(chǔ)服務(wù)提供者的注冊(cè)
核心類的實(shí)例化
請(qǐng)求實(shí)例化階段
實(shí)例化 Request 實(shí)例
請(qǐng)求處理階段
準(zhǔn)備請(qǐng)求處理的環(huán)境
將請(qǐng)求實(shí)例通過中間件處理 及 通過路由和控制器的分發(fā)控制
響應(yīng)發(fā)送和程序終止階段
將響應(yīng)內(nèi)容返回給客戶端
記錄與客戶端有關(guān)的信息等
1. 程序啟動(dòng)準(zhǔn)備程序入口在 index.php 中
require __DIR__."/../vendor/autoload.php"; $app = require_once __DIR__."/../bootstrap/app.php"; # 獲取服務(wù)容器實(shí)例 $kernel = $app->make(IlluminateContractsHttpKernel::class); $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); $response->send(); $kernel->terminate($request, $response);
創(chuàng)建服務(wù)容器實(shí)例
服務(wù)容器的創(chuàng)建在 bootstrapapp.php 中進(jìn)行.
$app = new IlluminateFoundationApplication( realpath(__DIR__."/../") );1.1 容器基礎(chǔ)配置
容器 Application 的構(gòu)造函數(shù):
public function __construct($basePath = null) { if ($basePath) { $this->setBasePath($basePath); } $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); }
構(gòu)造函數(shù) 主要完成以下基本配置:
目錄路徑(綁定到容器中, 并提供類方法獲取子目錄)
public function setBasePath($basePath) { $this->basePath = rtrim($basePath, "/"); $this->bindPathsInContainer(); return $this; } protected function bindPathsInContainer() { $this->instance("path", $this->path()); $this->instance("path.base", $this->basePath()); $this->instance("path.lang", $this->langPath()); $this->instance("path.config", $this->configPath()); $this->instance("path.public", $this->publicPath()); $this->instance("path.storage", $this->storagePath()); $this->instance("path.database", $this->databasePath()); $this->instance("path.resources", $this->resourcePath()); $this->instance("path.bootstrap", $this->bootstrapPath()); }
綁定容器自身
protected function registerBaseBindings() { static::setInstance($this); $this->instance("app", $this); $this->instance(Container::class, $this); $this->instance(PackageManifest::class, new PackageManifest( new Filesystem, $this->basePath(), $this->getCachedPackagesPath() )); }
基礎(chǔ)服務(wù)注冊(cè)( Event, Log, Route)
protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new LogServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); }
別名注冊(cè)
多個(gè)接口名 對(duì)應(yīng)一個(gè)簡短別名, 后續(xù)在注冊(cè)服務(wù)時(shí)只需綁定到別名上即可 (而不必綁定到具體接口名)
public function registerCoreContainerAliases() { foreach ([ "app" => [IlluminateFoundationApplication::class, IlluminateContractsContainerContainer::class, IlluminateContractsFoundationApplication::class, PsrContainerContainerInterface::class], "auth" => [IlluminateAuthAuthManager::class, IlluminateContractsAuthFactory::class], "auth.driver" => [IlluminateContractsAuthGuard::class], "blade.compiler" => [IlluminateViewCompilersBladeCompiler::class], "cache" => [IlluminateCacheCacheManager::class, IlluminateContractsCacheFactory::class], "cache.store" => [IlluminateCacheRepository::class, IlluminateContractsCacheRepository::class], "config" => [IlluminateConfigRepository::class, IlluminateContractsConfigRepository::class], "cookie" => [IlluminateCookieCookieJar::class, IlluminateContractsCookieFactory::class, IlluminateContractsCookieQueueingFactory::class], "encrypter" => [IlluminateEncryptionEncrypter::class, IlluminateContractsEncryptionEncrypter::class], "db" => [IlluminateDatabaseDatabaseManager::class], "db.connection" => [IlluminateDatabaseConnection::class, IlluminateDatabaseConnectionInterface::class], "events" => [IlluminateEventsDispatcher::class, IlluminateContractsEventsDispatcher::class], "files" => [IlluminateFilesystemFilesystem::class], "filesystem" => [IlluminateFilesystemFilesystemManager::class, IlluminateContractsFilesystemFactory::class], "filesystem.disk" => [IlluminateContractsFilesystemFilesystem::class], "filesystem.cloud" => [IlluminateContractsFilesystemCloud::class], "hash" => [IlluminateContractsHashingHasher::class], "translator" => [IlluminateTranslationTranslator::class, IlluminateContractsTranslationTranslator::class], "log" => [IlluminateLogWriter::class, IlluminateContractsLoggingLog::class, PsrLogLoggerInterface::class], "mailer" => [IlluminateMailMailer::class, IlluminateContractsMailMailer::class, IlluminateContractsMailMailQueue::class], "auth.password" => [IlluminateAuthPasswordsPasswordBrokerManager::class, IlluminateContractsAuthPasswordBrokerFactory::class], "auth.password.broker" => [IlluminateAuthPasswordsPasswordBroker::class, IlluminateContractsAuthPasswordBroker::class], "queue" => [IlluminateQueueQueueManager::class, IlluminateContractsQueueFactory::class, IlluminateContractsQueueMonitor::class], "queue.connection" => [IlluminateContractsQueueQueue::class], "queue.failer" => [IlluminateQueueFailedFailedJobProviderInterface::class], "redirect" => [IlluminateRoutingRedirector::class], "redis" => [IlluminateRedisRedisManager::class, IlluminateContractsRedisFactory::class], "request" => [IlluminateHttpRequest::class, SymfonyComponentHttpFoundationRequest::class], "router" => [IlluminateRoutingRouter::class, IlluminateContractsRoutingRegistrar::class, IlluminateContractsRoutingBindingRegistrar::class], "session" => [IlluminateSessionSessionManager::class], "session.store" => [IlluminateSessionStore::class, IlluminateContractsSessionSession::class], "url" => [IlluminateRoutingUrlGenerator::class, IlluminateContractsRoutingUrlGenerator::class], "validator" => [IlluminateValidationFactory::class, IlluminateContractsValidationFactory::class], "view" => [IlluminateViewFactory::class, IlluminateContractsViewFactory::class], ] as $key => $aliases) { foreach ($aliases as $alias) { $this->alias($key, $alias); } } }1.2 核心類綁定
$app->singleton( IlluminateContractsHttpKernel::class, AppHttpKernel::class ); $app->singleton( IlluminateContractsConsoleKernel::class, AppConsoleKernel::class ); $app->singleton( IlluminateContractsDebugExceptionHandler::class, AppExceptionsHandler::class );
綁定重要接口:
Http 核心類
命令行 核心類
異常處理類
1.3 實(shí)例化 Http 核心類$kernel = $app->make(IlluminateContractsHttpKernel::class);
Http 核心類的構(gòu)造函數(shù)
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); } }
上述過程主要做的事是將中間件賦值給路由
中間件順序優(yōu)先級(jí)列表
中間件組
中間件別名
核心類 app/Http/Kernel.php
[ // Cookie 加密解密 AppHttpMiddlewareEncryptCookies::class, // 將 Cookie 添加到響應(yīng)中 IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class, // 開啟會(huì)話 IlluminateSessionMiddlewareStartSession::class, // 認(rèn)證用戶,此中間件以后 Auth 類才能生效 // 見:https://d.laravel-china.org/docs/5.5/authentication IlluminateSessionMiddlewareAuthenticateSession::class, // 將系統(tǒng)的錯(cuò)誤數(shù)據(jù)注入到視圖變量 $errors 中 IlluminateViewMiddlewareShareErrorsFromSession::class, // 檢驗(yàn) CSRF ,防止跨站請(qǐng)求偽造的安全威脅 // 見:https://d.laravel-china.org/docs/5.5/csrf AppHttpMiddlewareVerifyCsrfToken::class, // 處理路由綁定 // 見:https://d.laravel-china.org/docs/5.5/routing#route-model-binding IlluminateRoutingMiddlewareSubstituteBindings::class, ], // API 中間件組,應(yīng)用于 routes/api.php 路由文件 "api" => [ // 使用別名來調(diào)用中間件 // 請(qǐng)見:https://d.laravel-china.org/docs/5.5/middleware#為路由分配中間件 "throttle:60,1", "bindings", ], ]; // 中間件別名設(shè)置,允許你使用別名調(diào)用中間件,例如上面的 api 中間件組調(diào)用 protected $routeMiddleware = [ // 只有登錄用戶才能訪問,我們?cè)诳刂破鞯臉?gòu)造方法中大量使用 "auth" => IlluminateAuthMiddlewareAuthenticate::class, // HTTP Basic Auth 認(rèn)證 "auth.basic" => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class, // 處理路由綁定 // 見:https://d.laravel-china.org/docs/5.5/routing#route-model-binding "bindings" => IlluminateRoutingMiddlewareSubstituteBindings::class, // 用戶授權(quán)功能 "can" => IlluminateAuthMiddlewareAuthorize::class, // 只有游客才能訪問,在 register 和 login 請(qǐng)求中使用,只有未登錄用戶才能訪問這些頁面 "guest" => AppHttpMiddlewareRedirectIfAuthenticated::class, // 訪問節(jié)流,類似于 『1 分鐘只能請(qǐng)求 10 次』的需求,一般在 API 中使用 "throttle" => IlluminateRoutingMiddlewareThrottleRequests::class, ]; }2. 請(qǐng)求實(shí)例化
以處理 Http 請(qǐng)求為例
index.php 入口文件
$response = $kernel->handle( $request = IlluminateHttpRequest::capture() );
請(qǐng)求是通過 IlluminateHttpRequest::capture() 實(shí)例化的, 主要是將請(qǐng)求信息以對(duì)象形式表現(xiàn)出來
3. 請(qǐng)求處理入口文件:
$response = $kernel->handle( $request = IlluminateHttpRequest::capture() );
$kernel->handle(...) 處理請(qǐng)求過程
IlluminateFoundationHttpKernel
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; } 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()); } protected function dispatchToRouter() { return function ($request) { $this->app->instance("request", $request); return $this->router->dispatch($request); }; }
實(shí)際處理請(qǐng)求邏輯主要在 sendRequestThroughRouter 方法中, 它主要做了:
核心類的初始化
經(jīng)由中間件過濾后將請(qǐng)求最終交由 Router 處理
3.1 請(qǐng)求處理環(huán)境初始化對(duì)于 Http 請(qǐng)求處理, 中間件包括:
protected $middleware = [ IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class, IlluminateFoundationHttpMiddlewareValidatePostSize::class, AppHttpMiddlewareTrimStrings::class, IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class, AppHttpMiddlewareTrustProxies::class, ];該中間件數(shù)組定義在 Http 核心類中, 同時(shí)在核心類的構(gòu)造函數(shù)中傳遞給 Router 類
核心類的初始化 bootstrap()
protected $bootstrappers = [ IlluminateFoundationBootstrapLoadEnvironmentVariables::class, IlluminateFoundationBootstrapLoadConfiguration::class, IlluminateFoundationBootstrapHandleExceptions::class, IlluminateFoundationBootstrapRegisterFacades::class, IlluminateFoundationBootstrapRegisterProviders::class, IlluminateFoundationBootstrapBootProviders::class, ]; # 初始化 public function bootstrap() { if (! $this->app->hasBeenBootstrapped()) { $this->app->bootstrapWith($this->bootstrappers()); } } protected function bootstrappers() { return $this->bootstrappers; }
在服務(wù)容器 Application 類中
public function bootstrapWith(array $bootstrappers) { $this->hasBeenBootstrapped = true; foreach ($bootstrappers as $bootstrapper) { $this["events"]->fire("bootstrapping: ".$bootstrapper, [$this]); $this->make($bootstrapper)->bootstrap($this); $this["events"]->fire("bootstrapped: ".$bootstrapper, [$this]); } }
該步驟主要是主要是對(duì)核心類中定義的 $bootstrappers 數(shù)組元素(引導(dǎo)類)初始化.
bootstrap 過程具體是在服務(wù)容器來中進(jìn)行, 由核心類調(diào)用并傳入待初始化的類
Http 核心類默認(rèn)包含以下 6 個(gè)啟動(dòng)服務(wù):
1. 環(huán)境監(jiān)測(cè) IlluminateFoundationBootstrapLoadEnvironmentVariables::class從 .env 文件中解析環(huán)境變量到 getevn(), $_ENV, $_SERVER
依賴 vlucas/phpdotenv 擴(kuò)展包2. 配置加載 IlluminateFoundationBootstrapLoadConfiguration::class
載入 config 目錄下所有 php 配置文件, 并將生成的配置存儲(chǔ)類綁定到服務(wù)容器 $app["config"]
同時(shí)配置時(shí)區(qū)及 多字節(jié)格式(utf8)
3. 常處理 IlluminateFoundationBootstrapHandleExceptions::class報(bào)告所有錯(cuò)誤 error_report(E_ALL)
提供對(duì)未捕獲的異常, 錯(cuò)誤的全局處理 set_error_handler, set_exception_handler, register_shutdown_function
4. 外觀注冊(cè) IlluminateFoundationBootstrapRegisterFacades::class從 app.aliases 中讀取外觀配置數(shù)組
"aliases" => [ "App" => IlluminateSupportFacadesApp::class, "Artisan" => IlluminateSupportFacadesArtisan::class, "Auth" => IlluminateSupportFacadesAuth::class, "Blade" => IlluminateSupportFacadesBlade::class, "Broadcast" => IlluminateSupportFacadesBroadcast::class, "Bus" => IlluminateSupportFacadesBus::class, "Cache" => IlluminateSupportFacadesCache::class, "Config" => IlluminateSupportFacadesConfig::class, "Cookie" => IlluminateSupportFacadesCookie::class, "Crypt" => IlluminateSupportFacadesCrypt::class, "DB" => IlluminateSupportFacadesDB::class, "Eloquent" => IlluminateDatabaseEloquentModel::class, "Event" => IlluminateSupportFacadesEvent::class, "File" => IlluminateSupportFacadesFile::class, "Gate" => IlluminateSupportFacadesGate::class, "Hash" => IlluminateSupportFacadesHash::class, "Lang" => IlluminateSupportFacadesLang::class, "Log" => IlluminateSupportFacadesLog::class, "Mail" => IlluminateSupportFacadesMail::class, "Notification" => IlluminateSupportFacadesNotification::class, "Password" => IlluminateSupportFacadesPassword::class, "Queue" => IlluminateSupportFacadesQueue::class, "Redirect" => IlluminateSupportFacadesRedirect::class, "Redis" => IlluminateSupportFacadesRedis::class, "Request" => IlluminateSupportFacadesRequest::class, "Response" => IlluminateSupportFacadesResponse::class, "Route" => IlluminateSupportFacadesRoute::class, "Schema" => IlluminateSupportFacadesSchema::class, "Session" => IlluminateSupportFacadesSession::class, "Storage" => IlluminateSupportFacadesStorage::class, "URL" => IlluminateSupportFacadesURL::class, "Validator" => IlluminateSupportFacadesValidator::class, "View" => IlluminateSupportFacadesView::class, ],
使用 spl_autoload_register(...) 處理類加載, 配合 class_alias() 提供類的別名調(diào)用
Facade 外觀類基類依賴 __callStatic` 調(diào)用方法( 使用服務(wù)容器實(shí)例化對(duì)應(yīng)類)
5. 服務(wù)提供者注冊(cè) IlluminateFoundationBootstrapRegisterProviders::class從 app.providers 中讀取所有服務(wù)提供者
"providers" => [ /* * Laravel Framework Service Providers... */ IlluminateAuthAuthServiceProvider::class, IlluminateBroadcastingBroadcastServiceProvider::class, IlluminateBusBusServiceProvider::class, IlluminateCacheCacheServiceProvider::class, IlluminateFoundationProvidersConsoleSupportServiceProvider::class, IlluminateCookieCookieServiceProvider::class, IlluminateDatabaseDatabaseServiceProvider::class, IlluminateEncryptionEncryptionServiceProvider::class, IlluminateFilesystemFilesystemServiceProvider::class, IlluminateFoundationProvidersFoundationServiceProvider::class, IlluminateHashingHashServiceProvider::class, IlluminateMailMailServiceProvider::class, IlluminateNotificationsNotificationServiceProvider::class, IlluminatePaginationPaginationServiceProvider::class, IlluminatePipelinePipelineServiceProvider::class, IlluminateQueueQueueServiceProvider::class, IlluminateRedisRedisServiceProvider::class, IlluminateAuthPasswordsPasswordResetServiceProvider::class, IlluminateSessionSessionServiceProvider::class, IlluminateTranslationTranslationServiceProvider::class, IlluminateValidationValidationServiceProvider::class, IlluminateViewViewServiceProvider::class, /* * Package Service Providers... */ /* * Application Service Providers... */ AppProvidersAppServiceProvider::class, AppProvidersAuthServiceProvider::class, // AppProvidersBroadcastServiceProvider::class, AppProvidersEventServiceProvider::class, AppProvidersRouteServiceProvider::class, # 路由表生成 ],
服務(wù)提供者經(jīng)過解析后分為 3 種類型的服務(wù)提供者:
eager 類型
馬上調(diào)用 register 注冊(cè)
deferred 類型
記錄下來, 當(dāng)服務(wù)容器解析對(duì)應(yīng)服務(wù)時(shí), 才注冊(cè)對(duì)應(yīng)的服務(wù)提供者
when 類型
記錄下來, 當(dāng)對(duì)應(yīng) event 觸發(fā)時(shí)在注冊(cè)對(duì)應(yīng)服務(wù)提供者
6. 啟動(dòng)提供者 IlluminateFoundationBootstrapBootProviders::class調(diào)用服務(wù)容器的 boot() 方法, 依次調(diào)用在服務(wù)容器中 register 的所有服務(wù)提供者的 boot() 方法
3.2 路由處理請(qǐng)求在內(nèi)核處理請(qǐng)求, 將請(qǐng)求實(shí)例通過中間件處理后, 將請(qǐng)求的處理交給路由 Router 進(jìn)行控制器的分發(fā).
Http Kernel
protected function dispatchToRouter() { return function ($request) { $this->app->instance("request", $request); return $this->router->dispatch($request); }; }
路由表存儲(chǔ)結(jié)構(gòu)說明
IlluminateRoutingRoute 存儲(chǔ)單條路由IlluminateRoutingRouteCollection 保存所有 Route 實(shí)例, 形成路由表
IlluminateRoutingRouter 類實(shí)例持有 RouteCollection 路由表實(shí)例.
即, 一個(gè) Router 持有一個(gè) RouteCollection, 而 RouteCollection 擁有 N 個(gè) Route
在 Router 中對(duì)請(qǐng)求的處理同樣經(jīng)過一系列的 路由中間件
# 路由處理請(qǐng)求的入庫 public function dispatchToRoute(Request $request) { return $this->runRoute($request, $this->findRoute($request)); } # 根據(jù)請(qǐng)求的 url 和 method 查找對(duì)應(yīng)的 route protected function findRoute($request) { $this->current = $route = $this->routes->match($request); $this->container->instance(Route::class, $route); return $route; } # 根據(jù)對(duì)應(yīng)的請(qǐng)求和路由條目, 返回相應(yīng)的 $response protected function runRoute(Request $request, Route $route) { $request->setRouteResolver(function () use ($route) { return $route; }); $this->events->dispatch(new EventsRouteMatched($route, $request)); return $this->prepareResponse($request, $this->runRouteWithinStack($route, $request) ); } # 請(qǐng)求經(jīng)過路由中間件過濾后, 交由 route 的 run() 方法處理 protected function runRouteWithinStack(Route $route, Request $request) { $shouldSkipMiddleware = $this->container->bound("middleware.disable") && $this->container->make("middleware.disable") === true; $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddleware($route); return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run() ); }); }
route 的 run() 方法最終將請(qǐng)求轉(zhuǎn)給 IlluminateRoutingControllerDispatcher::dispatch 處理
public function dispatch(Route $route, $controller, $method) { $parameters = $this->resolveClassMethodDependencies( $route->parametersWithoutNulls(), $controller, $method ); if (method_exists($controller, "callAction")) { return $controller->callAction($method, $parameters); } return $controller->{$method}(...array_values($parameters)); }
剩下的事情就是 Controller控制器 的事了.
3.3 處理返回的 Response在 Router 中有一個(gè)方法, 用于對(duì)返回的 $response 進(jìn)行處理
public function prepareResponse($request, $response) { return static::toResponse($request, $response); } /** * @return IlluminateHttpResponse|IlluminateHttpJsonResponse */ public static function toResponse($request, $response) { if ($response instanceof Responsable) { $response = $response->toResponse($request); } if ($response instanceof PsrResponseInterface) { $response = (new HttpFoundationFactory)->createResponse($response); } elseif (! $response instanceof SymfonyResponse && ($response instanceof Arrayable || $response instanceof Jsonable || $response instanceof ArrayObject || $response instanceof JsonSerializable || is_array($response))) { $response = new JsonResponse($response); } elseif (! $response instanceof SymfonyResponse) { $response = new Response($response); } if ($response->getStatusCode() === Response::HTTP_NOT_MODIFIED) { $response->setNotModified(); } return $response->prepare($request); # 最后的處理 }
上述過程中, 在返回 $response 之前進(jìn)行了最后的處理 $response->prepare($request)
該過程是在 SymfonyComponentHttpFoundationResponse::prepare() 中進(jìn)行
對(duì)響應(yīng)的封裝是通過 IlluminateHttpResponse 類完成, 該類底層是 Symfony 框架的 Response 類即, SymfonyComponentHttpFoundationResponse
public function prepare(Request $request) { $headers = $this->headers; if ($this->isInformational() || $this->isEmpty()) { $this->setContent(null); $headers->remove("Content-Type"); $headers->remove("Content-Length"); } else { // Content-type based on the Request if (!$headers->has("Content-Type")) { $format = $request->getRequestFormat(); if (null !== $format && $mimeType = $request->getMimeType($format)) { $headers->set("Content-Type", $mimeType); } } // Fix Content-Type $charset = $this->charset ?: "UTF-8"; if (!$headers->has("Content-Type")) { $headers->set("Content-Type", "text/html; charset=".$charset); } elseif (0 === stripos($headers->get("Content-Type"), "text/") && false === stripos($headers->get("Content-Type"), "charset")) { // add the charset $headers->set("Content-Type", $headers->get("Content-Type")."; charset=".$charset); } // Fix Content-Length if ($headers->has("Transfer-Encoding")) { $headers->remove("Content-Length"); } if ($request->isMethod("HEAD")) { // cf. RFC2616 14.13 $length = $headers->get("Content-Length"); $this->setContent(null); if ($length) { $headers->set("Content-Length", $length); } } } // Fix protocol if ("HTTP/1.0" != $request->server->get("SERVER_PROTOCOL")) { $this->setProtocolVersion("1.1"); } // Check if we need to send extra expire info headers if ("1.0" == $this->getProtocolVersion() && false !== strpos($this->headers->get("Cache-Control"), "no-cache")) { $this->headers->set("pragma", "no-cache"); $this->headers->set("expires", -1); } $this->ensureIEOverSSLCompatibility($request); return $this; }4. 響應(yīng)發(fā)送和程序終止 4.1 響應(yīng)的發(fā)送
在 index.php 入口文件的最后是將響應(yīng)返回給客戶端
$response->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; } public function sendHeaders() { // headers have already been sent by the developer if (headers_sent()) { return $this; } // headers foreach ($this->headers->allPreserveCase() as $name => $values) { foreach ($values as $value) { header($name.": ".$value, false, $this->statusCode); } } // status header(sprintf("HTTP/%s %s %s", $this->version, $this->statusCode, $this->statusText), true, $this->statusCode); return $this; } public function sendContent() { echo $this->content; return $this; }4.2 請(qǐng)求中止
在 index.php 入口文件的最后:
$kernel->terminate($request, $response);
依舊以 Http Kernel 為例:
public function terminate($request, $response) { $this->terminateMiddleware($request, $response); # 中間件中止處理 $this->app->terminate(); # 服務(wù)容器的中止處理函數(shù) } 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) = $this->parseMiddleware($middleware); $instance = $this->app->make($name); if (method_exists($instance, "terminate")) { $instance->terminate($request, $response); } } }
此處的中間件指的是定義在 Kernel 中的 $middleware 中間件數(shù)組列表, 不包含 路由中間件.
Laravel 5.1 注: 默認(rèn)只有會(huì)話中間件包含 terminate() 函數(shù)
Application 服務(wù)容器的中止處理函數(shù)
public function terminate() { foreach ($this->terminatingCallbacks as $terminating) { $this->call($terminating); } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/31436.html
摘要:但是不用擔(dān)心,我們后續(xù)的教程會(huì)陸續(xù)講解相關(guān)的內(nèi)容。所以上面的路由注冊(cè)其實(shí)就是負(fù)責(zé)解決訪問的時(shí)候的響應(yīng)。 原文來自:https://jellybool.com/post/programming-with-laravel-5-routers-views-controllers-workflow 免費(fèi)視頻教程地址 https://laravist.com/series/laravel-5-b...
摘要:直到所有中間件都執(zhí)行完畢,最后在執(zhí)行最后的即上述的方法如果上述有地方難懂的,可以參考這邊文章內(nèi)置函數(shù)在中的使用以上是在通過全局中間件時(shí)的大致流程,通過中間件和路由中間件也是一樣的,都是采用管道流操作,詳情可翻閱源碼 簡介 Laravel 中間件提供了一種方便的機(jī)制來過濾進(jìn)入應(yīng)用的 HTTP 請(qǐng)求, 如ValidatePostSize用來驗(yàn)證POST請(qǐng)求體大小、ThrottleReque...
摘要:最佳實(shí)踐良好的編碼規(guī)范單元測(cè)試持續(xù)集成文檔,從一開始就形成良好的編碼習(xí)慣。真實(shí)的電商業(yè)務(wù)所有的業(yè)務(wù)需求來自真實(shí)的客戶,并且線上良好運(yùn)營中。 重要通知: Laravel + 小程序的開源電商版本源碼已經(jīng)在 github 上拉,歡迎提交 issue 和 star :) 開源電商 Server 端: Laravel API源碼 開源電商 client 端:小程序源碼 iBrand 簡介...
摘要:至于其他的算一般我習(xí)慣說樹形模型,這里說的概率模型可能是差不多的意思。 要點(diǎn) 不同工具之間版本匹配很重要由點(diǎn)及面,先實(shí)踐起來再學(xué)細(xì)節(jié)的原理和使用 技術(shù)棧 laravel5.5框架+scout組件+elasticsearch6.3.0搜索引擎 輔助 elasticsearch-head 查看集群數(shù)據(jù)可視化 中文分詞插件Ik 介紹 laravel是一款現(xiàn)代化的php框架es是搜索引擎e...
閱讀 3865·2021-09-23 11:51
閱讀 3057·2021-09-22 15:59
閱讀 856·2021-09-09 11:37
閱讀 2064·2021-09-08 09:45
閱讀 1260·2019-08-30 15:54
閱讀 2056·2019-08-30 15:53
閱讀 485·2019-08-29 12:12
閱讀 3283·2019-08-29 11:15