摘要:年月日階段劃分請求到響應的整個執行階段歸納為個程序啟動準備階段文件自動加載服務容器實例化基礎服務提供者的注冊核心類的實例化請求實例化階段實例化實例請求處理階段準備請求處理的環境將請求實例通過中間件處理及通過路由和控制器的分發控制響應發送和
Last-Modified: 2019年5月10日16:19:07
階段劃分Laravel 5.5
請求到響應的整個執行階段歸納為 4 個:
程序啟動準備階段
文件自動加載
服務容器實例化
基礎服務提供者的注冊
核心類的實例化
請求實例化階段
實例化 Request 實例
請求處理階段
準備請求處理的環境
將請求實例通過中間件處理 及 通過路由和控制器的分發控制
響應發送和程序終止階段
將響應內容返回給客戶端
記錄與客戶端有關的信息等
1. 程序啟動準備程序入口在 index.php 中
require __DIR__."/../vendor/autoload.php"; $app = require_once __DIR__."/../bootstrap/app.php"; # 獲取服務容器實例 $kernel = $app->make(IlluminateContractsHttpKernel::class); $response = $kernel->handle( $request = IlluminateHttpRequest::capture() ); $response->send(); $kernel->terminate($request, $response);
創建服務容器實例
服務容器的創建在 bootstrapapp.php 中進行.
$app = new IlluminateFoundationApplication( realpath(__DIR__."/../") );1.1 容器基礎配置
容器 Application 的構造函數:
public function __construct($basePath = null) { if ($basePath) { $this->setBasePath($basePath); } $this->registerBaseBindings(); $this->registerBaseServiceProviders(); $this->registerCoreContainerAliases(); }
構造函數 主要完成以下基本配置:
目錄路徑(綁定到容器中, 并提供類方法獲取子目錄)
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() )); }
基礎服務注冊( Event, Log, Route)
protected function registerBaseServiceProviders() { $this->register(new EventServiceProvider($this)); $this->register(new LogServiceProvider($this)); $this->register(new RoutingServiceProvider($this)); }
別名注冊
多個接口名 對應一個簡短別名, 后續在注冊服務時只需綁定到別名上即可 (而不必綁定到具體接口名)
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 實例化 Http 核心類$kernel = $app->make(IlluminateContractsHttpKernel::class);
Http 核心類的構造函數
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); } }
上述過程主要做的事是將中間件賦值給路由
中間件順序優先級列表
中間件組
中間件別名
核心類 app/Http/Kernel.php
[ // Cookie 加密解密 AppHttpMiddlewareEncryptCookies::class, // 將 Cookie 添加到響應中 IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class, // 開啟會話 IlluminateSessionMiddlewareStartSession::class, // 認證用戶,此中間件以后 Auth 類才能生效 // 見:https://d.laravel-china.org/docs/5.5/authentication IlluminateSessionMiddlewareAuthenticateSession::class, // 將系統的錯誤數據注入到視圖變量 $errors 中 IlluminateViewMiddlewareShareErrorsFromSession::class, // 檢驗 CSRF ,防止跨站請求偽造的安全威脅 // 見: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 中間件組,應用于 routes/api.php 路由文件 "api" => [ // 使用別名來調用中間件 // 請見:https://d.laravel-china.org/docs/5.5/middleware#為路由分配中間件 "throttle:60,1", "bindings", ], ]; // 中間件別名設置,允許你使用別名調用中間件,例如上面的 api 中間件組調用 protected $routeMiddleware = [ // 只有登錄用戶才能訪問,我們在控制器的構造方法中大量使用 "auth" => IlluminateAuthMiddlewareAuthenticate::class, // HTTP Basic Auth 認證 "auth.basic" => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class, // 處理路由綁定 // 見:https://d.laravel-china.org/docs/5.5/routing#route-model-binding "bindings" => IlluminateRoutingMiddlewareSubstituteBindings::class, // 用戶授權功能 "can" => IlluminateAuthMiddlewareAuthorize::class, // 只有游客才能訪問,在 register 和 login 請求中使用,只有未登錄用戶才能訪問這些頁面 "guest" => AppHttpMiddlewareRedirectIfAuthenticated::class, // 訪問節流,類似于 『1 分鐘只能請求 10 次』的需求,一般在 API 中使用 "throttle" => IlluminateRoutingMiddlewareThrottleRequests::class, ]; }2. 請求實例化
以處理 Http 請求為例
index.php 入口文件
$response = $kernel->handle( $request = IlluminateHttpRequest::capture() );
請求是通過 IlluminateHttpRequest::capture() 實例化的, 主要是將請求信息以對象形式表現出來
3. 請求處理入口文件:
$response = $kernel->handle( $request = IlluminateHttpRequest::capture() );
$kernel->handle(...) 處理請求過程
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); }; }
實際處理請求邏輯主要在 sendRequestThroughRouter 方法中, 它主要做了:
核心類的初始化
經由中間件過濾后將請求最終交由 Router 處理
3.1 請求處理環境初始化對于 Http 請求處理, 中間件包括:
protected $middleware = [ IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class, IlluminateFoundationHttpMiddlewareValidatePostSize::class, AppHttpMiddlewareTrimStrings::class, IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class, AppHttpMiddlewareTrustProxies::class, ];該中間件數組定義在 Http 核心類中, 同時在核心類的構造函數中傳遞給 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; }
在服務容器 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]); } }
該步驟主要是主要是對核心類中定義的 $bootstrappers 數組元素(引導類)初始化.
bootstrap 過程具體是在服務容器來中進行, 由核心類調用并傳入待初始化的類
Http 核心類默認包含以下 6 個啟動服務:
1. 環境監測 IlluminateFoundationBootstrapLoadEnvironmentVariables::class從 .env 文件中解析環境變量到 getevn(), $_ENV, $_SERVER
依賴 vlucas/phpdotenv 擴展包2. 配置加載 IlluminateFoundationBootstrapLoadConfiguration::class
載入 config 目錄下所有 php 配置文件, 并將生成的配置存儲類綁定到服務容器 $app["config"]
同時配置時區及 多字節格式(utf8)
3. 常處理 IlluminateFoundationBootstrapHandleExceptions::class報告所有錯誤 error_report(E_ALL)
提供對未捕獲的異常, 錯誤的全局處理 set_error_handler, set_exception_handler, register_shutdown_function
4. 外觀注冊 IlluminateFoundationBootstrapRegisterFacades::class從 app.aliases 中讀取外觀配置數組
"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() 提供類的別名調用
Facade 外觀類基類依賴 __callStatic` 調用方法( 使用服務容器實例化對應類)
5. 服務提供者注冊 IlluminateFoundationBootstrapRegisterProviders::class從 app.providers 中讀取所有服務提供者
"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, # 路由表生成 ],
服務提供者經過解析后分為 3 種類型的服務提供者:
eager 類型
馬上調用 register 注冊
deferred 類型
記錄下來, 當服務容器解析對應服務時, 才注冊對應的服務提供者
when 類型
記錄下來, 當對應 event 觸發時在注冊對應服務提供者
6. 啟動提供者 IlluminateFoundationBootstrapBootProviders::class調用服務容器的 boot() 方法, 依次調用在服務容器中 register 的所有服務提供者的 boot() 方法
3.2 路由處理請求在內核處理請求, 將請求實例通過中間件處理后, 將請求的處理交給路由 Router 進行控制器的分發.
Http Kernel
protected function dispatchToRouter() { return function ($request) { $this->app->instance("request", $request); return $this->router->dispatch($request); }; }
路由表存儲結構說明
IlluminateRoutingRoute 存儲單條路由IlluminateRoutingRouteCollection 保存所有 Route 實例, 形成路由表
IlluminateRoutingRouter 類實例持有 RouteCollection 路由表實例.
即, 一個 Router 持有一個 RouteCollection, 而 RouteCollection 擁有 N 個 Route
在 Router 中對請求的處理同樣經過一系列的 路由中間件
# 路由處理請求的入庫 public function dispatchToRoute(Request $request) { return $this->runRoute($request, $this->findRoute($request)); } # 根據請求的 url 和 method 查找對應的 route protected function findRoute($request) { $this->current = $route = $this->routes->match($request); $this->container->instance(Route::class, $route); return $route; } # 根據對應的請求和路由條目, 返回相應的 $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) ); } # 請求經過路由中間件過濾后, 交由 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() 方法最終將請求轉給 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 中有一個方法, 用于對返回的 $response 進行處理
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 之前進行了最后的處理 $response->prepare($request)
該過程是在 SymfonyComponentHttpFoundationResponse::prepare() 中進行
對響應的封裝是通過 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. 響應發送和程序終止 4.1 響應的發送
在 index.php 入口文件的最后是將響應返回給客戶端
$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 請求中止
在 index.php 入口文件的最后:
$kernel->terminate($request, $response);
依舊以 Http Kernel 為例:
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) = $this->parseMiddleware($middleware); $instance = $this->app->make($name); if (method_exists($instance, "terminate")) { $instance->terminate($request, $response); } } }
此處的中間件指的是定義在 Kernel 中的 $middleware 中間件數組列表, 不包含 路由中間件.
Laravel 5.1 注: 默認只有會話中間件包含 terminate() 函數
Application 服務容器的中止處理函數
public function terminate() { foreach ($this->terminatingCallbacks as $terminating) { $this->call($terminating); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/31436.html
摘要:但是不用擔心,我們后續的教程會陸續講解相關的內容。所以上面的路由注冊其實就是負責解決訪問的時候的響應。 原文來自:https://jellybool.com/post/programming-with-laravel-5-routers-views-controllers-workflow 免費視頻教程地址 https://laravist.com/series/laravel-5-b...
摘要:直到所有中間件都執行完畢,最后在執行最后的即上述的方法如果上述有地方難懂的,可以參考這邊文章內置函數在中的使用以上是在通過全局中間件時的大致流程,通過中間件和路由中間件也是一樣的,都是采用管道流操作,詳情可翻閱源碼 簡介 Laravel 中間件提供了一種方便的機制來過濾進入應用的 HTTP 請求, 如ValidatePostSize用來驗證POST請求體大小、ThrottleReque...
摘要:最佳實踐良好的編碼規范單元測試持續集成文檔,從一開始就形成良好的編碼習慣。真實的電商業務所有的業務需求來自真實的客戶,并且線上良好運營中。 重要通知: Laravel + 小程序的開源電商版本源碼已經在 github 上拉,歡迎提交 issue 和 star :) 開源電商 Server 端: Laravel API源碼 開源電商 client 端:小程序源碼 iBrand 簡介...
摘要:至于其他的算一般我習慣說樹形模型,這里說的概率模型可能是差不多的意思。 要點 不同工具之間版本匹配很重要由點及面,先實踐起來再學細節的原理和使用 技術棧 laravel5.5框架+scout組件+elasticsearch6.3.0搜索引擎 輔助 elasticsearch-head 查看集群數據可視化 中文分詞插件Ik 介紹 laravel是一款現代化的php框架es是搜索引擎e...
閱讀 3880·2021-09-23 11:51
閱讀 3067·2021-09-22 15:59
閱讀 868·2021-09-09 11:37
閱讀 2070·2021-09-08 09:45
閱讀 1267·2019-08-30 15:54
閱讀 2065·2019-08-30 15:53
閱讀 492·2019-08-29 12:12
閱讀 3290·2019-08-29 11:15