- 1. 程序启动准备
- 2. 请求实例化
- 3. 请求处理
- 3.1 请求处理环境初始化
- 1. 环境监测 IlluminateFoundationBootstrapLoadEnvironmentVariables::class
- 2. 配置加载 IlluminateFoundationBootstrapLoadConfiguration::class
- 3. 常处理 IlluminateFoundationBootstrapHandleExceptions::class
- 4. 外观注册 IlluminateFoundationBootstrapRegisterFacades::class
- 5. 服务提供者注册 IlluminateFoundationBootstrapRegisterProviders::class
- 6. 启动提供者 IlluminateFoundationBootstrapBootProviders::class
- 3.2 路由处理请求
- 3.3 处理返回的 Response
- 3.1 请求处理环境初始化
- 4. 响应发送和程序终止
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
<?php
namespace AppHttp;
use IlluminateFoundationHttpKernel as HttpKernel;
class Kernel extends HttpKernel
{
// 全局中间件,最先调用
protected $middleware = [
// 检测是否应用是否进入『维护模式』
// 见:https://d.laravel-china.org/docs/5.5/configuration#maintenance-mode
IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class,
// 检测请求的数据是否过大
IlluminateFoundationHttpMiddlewareValidatePostSize::class,
// 对提交的请求参数进行 PHP 函数 `trim()` 处理
AppHttpMiddlewareTrimStrings::class,
// 将提交请求参数中空子串转换为 null
IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class,
// 修正代理服务器后的服务器参数
AppHttpMiddlewareTrustProxies::class,
];
// 定义中间件组
protected $middlewareGroups = [
// Web 中间件组,应用于 routes/web.php 路由文件
'web' => [
// 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
处理对于 Http 请求处理, 中间件包括:
protected $middleware = [ IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class, IlluminateFoundationHttpMiddlewareValidatePostSize::class, AppHttpMiddlewareTrimStrings::class, IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class, AppHttpMiddlewareTrustProxies::class, ];
该中间件数组定义在 Http 核心类中, 同时在核心类的构造函数中传递给
Router
类
3.1 请求处理环境初始化
核心类的初始化 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);
}
}