Laravel 5.5

请求到响应的整个执行阶段归纳为 4 个:

  1. 程序启动准备阶段

    • 文件自动加载
    • 服务容器实例化
    • 基础服务提供者的注册
    • 核心类的实例化
  2. 请求实例化阶段
    • 实例化 Request 实例
  3. 请求处理阶段
    • 准备请求处理的环境
    • 将请求实例通过中间件处理 及 通过路由和控制器的分发控制
  4. 响应发送和程序终止阶段
    • 将响应内容返回给客户端
    • 记录与客户端有关的信息等

1. 程序启动准备

程序入口在 index.php

require __DIR__.'/../vendor/autoload.php';

$app = require_once __DIR__.'/../bootstrap/app.php';	# 获取服务容器实例

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
); $response->send(); $kernel->terminate($request, $response);

创建服务容器实例

服务容器的创建在 bootstrap\app.php 中进行.

$app = new Illuminate\Foundation\Application(
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' => [\Illuminate\Foundation\Application::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
    'auth' => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
    'auth.driver' => [\Illuminate\Contracts\Auth\Guard::class],
    'blade.compiler' => [\Illuminate\View\Compilers\BladeCompiler::class],
    'cache' => [\Illuminate\Cache\CacheManager::class, \Illuminate\Contracts\Cache\Factory::class],
    'cache.store' => [\Illuminate\Cache\Repository::class, \Illuminate\Contracts\Cache\Repository::class],
    'config' => [\Illuminate\Config\Repository::class, \Illuminate\Contracts\Config\Repository::class],
    'cookie' => [\Illuminate\Cookie\CookieJar::class, \Illuminate\Contracts\Cookie\Factory::class, \Illuminate\Contracts\Cookie\QueueingFactory::class],
    'encrypter' => [\Illuminate\Encryption\Encrypter::class, \Illuminate\Contracts\Encryption\Encrypter::class],
    'db' => [\Illuminate\Database\DatabaseManager::class],
    'db.connection' => [\Illuminate\Database\Connection::class, \Illuminate\Database\ConnectionInterface::class],
    'events' => [\Illuminate\Events\Dispatcher::class, \Illuminate\Contracts\Events\Dispatcher::class],
    'files' => [\Illuminate\Filesystem\Filesystem::class],
    'filesystem' => [\Illuminate\Filesystem\FilesystemManager::class, \Illuminate\Contracts\Filesystem\Factory::class],
    'filesystem.disk' => [\Illuminate\Contracts\Filesystem\Filesystem::class],
    'filesystem.cloud' => [\Illuminate\Contracts\Filesystem\Cloud::class],
    'hash' => [\Illuminate\Contracts\Hashing\Hasher::class],
    'translator' => [\Illuminate\Translation\Translator::class, \Illuminate\Contracts\Translation\Translator::class],
    'log' => [\Illuminate\Log\Writer::class, \Illuminate\Contracts\Logging\Log::class, \Psr\Log\LoggerInterface::class],
    'mailer' => [\Illuminate\Mail\Mailer::class, \Illuminate\Contracts\Mail\Mailer::class, \Illuminate\Contracts\Mail\MailQueue::class],
    'auth.password' => [\Illuminate\Auth\Passwords\PasswordBrokerManager::class, \Illuminate\Contracts\Auth\PasswordBrokerFactory::class],
    'auth.password.broker' => [\Illuminate\Auth\Passwords\PasswordBroker::class, \Illuminate\Contracts\Auth\PasswordBroker::class],
    'queue' => [\Illuminate\Queue\QueueManager::class, \Illuminate\Contracts\Queue\Factory::class, \Illuminate\Contracts\Queue\Monitor::class],
    'queue.connection' => [\Illuminate\Contracts\Queue\Queue::class],
    'queue.failer' => [\Illuminate\Queue\Failed\FailedJobProviderInterface::class],
    'redirect' => [\Illuminate\Routing\Redirector::class],
    'redis' => [\Illuminate\Redis\RedisManager::class, \Illuminate\Contracts\Redis\Factory::class],
    'request' => [\Illuminate\Http\Request::class, \Symfony\Component\HttpFoundation\Request::class],
    'router' => [\Illuminate\Routing\Router::class, \Illuminate\Contracts\Routing\Registrar::class, \Illuminate\Contracts\Routing\BindingRegistrar::class],
    'session' => [\Illuminate\Session\SessionManager::class],
    'session.store' => [\Illuminate\Session\Store::class, \Illuminate\Contracts\Session\Session::class],
    'url' => [\Illuminate\Routing\UrlGenerator::class, \Illuminate\Contracts\Routing\UrlGenerator::class],
    'validator' => [\Illuminate\Validation\Factory::class, \Illuminate\Contracts\Validation\Factory::class],
    'view' => [\Illuminate\View\Factory::class, \Illuminate\Contracts\View\Factory::class],
    ] as $key => $aliases) {
    foreach ($aliases as $alias) {
    $this->alias($key, $alias);
    }
    }
    }

1.2 核心类绑定

$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
); $app->singleton(
Illuminate\Contracts\Console\Kernel::class,
App\Console\Kernel::class
); $app->singleton(
Illuminate\Contracts\Debug\ExceptionHandler::class,
App\Exceptions\Handler::class
);

绑定重要接口:

  • Http 核心类
  • 命令行 核心类
  • 异常处理类

1.3 实例化 Http 核心类

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::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 App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
// 全局中间件,最先调用
protected $middleware = [ // 检测是否应用是否进入『维护模式』
// 见:https://d.laravel-china.org/docs/5.5/configuration#maintenance-mode
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class, // 检测请求的数据是否过大
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, // 对提交的请求参数进行 PHP 函数 `trim()` 处理
\App\Http\Middleware\TrimStrings::class, // 将提交请求参数中空子串转换为 null
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, // 修正代理服务器后的服务器参数
\App\Http\Middleware\TrustProxies::class,
]; // 定义中间件组
protected $middlewareGroups = [ // Web 中间件组,应用于 routes/web.php 路由文件
'web' => [
// Cookie 加密解密
\App\Http\Middleware\EncryptCookies::class, // 将 Cookie 添加到响应中
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, // 开启会话
\Illuminate\Session\Middleware\StartSession::class, // 认证用户,此中间件以后 Auth 类才能生效
// 见:https://d.laravel-china.org/docs/5.5/authentication
\Illuminate\Session\Middleware\AuthenticateSession::class, // 将系统的错误数据注入到视图变量 $errors 中
\Illuminate\View\Middleware\ShareErrorsFromSession::class, // 检验 CSRF ,防止跨站请求伪造的安全威胁
// 见:https://d.laravel-china.org/docs/5.5/csrf
\App\Http\Middleware\VerifyCsrfToken::class, // 处理路由绑定
// 见:https://d.laravel-china.org/docs/5.5/routing#route-model-binding
\Illuminate\Routing\Middleware\SubstituteBindings::class,
], // API 中间件组,应用于 routes/api.php 路由文件
'api' => [
// 使用别名来调用中间件
// 请见:https://d.laravel-china.org/docs/5.5/middleware#为路由分配中间件
'throttle:60,1',
'bindings',
],
]; // 中间件别名设置,允许你使用别名调用中间件,例如上面的 api 中间件组调用
protected $routeMiddleware = [ // 只有登录用户才能访问,我们在控制器的构造方法中大量使用
'auth' => \Illuminate\Auth\Middleware\Authenticate::class, // HTTP Basic Auth 认证
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, // 处理路由绑定
// 见:https://d.laravel-china.org/docs/5.5/routing#route-model-binding
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class, // 用户授权功能
'can' => \Illuminate\Auth\Middleware\Authorize::class, // 只有游客才能访问,在 register 和 login 请求中使用,只有未登录用户才能访问这些页面
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, // 访问节流,类似于 『1 分钟只能请求 10 次』的需求,一般在 API 中使用
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
];
}

2. 请求实例化

以处理 Http 请求为例

index.php 入口文件

$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);

请求是通过 Illuminate\Http\Request::capture() 实例化的, 主要是将请求信息以对象形式表现出来

3. 请求处理

入口文件:

$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);

$kernel->handle(...) 处理请求过程

Illuminate\Foundation\Http\Kernel

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 Events\RequestHandled($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 = [
    
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
    
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
    
        \App\Http\Middleware\TrimStrings::class,
    
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
    
        \App\Http\Middleware\TrustProxies::class,
    
    ];
    
    

    该中间件数组定义在 Http 核心类中, 同时在核心类的构造函数中传递给 Router

3.1 请求处理环境初始化

核心类的初始化 bootstrap()

protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
\Illuminate\Foundation\Bootstrap\BootProviders::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. 环境监测 \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class

.env 文件中解析环境变量到 getevn(), $_ENV, $_SERVER

依赖 vlucas/phpdotenv 扩展包

2. 配置加载 \Illuminate\Foundation\Bootstrap\LoadConfiguration::class

载入 config 目录下所有 php 配置文件, 并将生成的配置存储类绑定到服务容器 $app['config']

同时配置时区及 多字节格式(utf8)

3. 常处理 \Illuminate\Foundation\Bootstrap\HandleExceptions::class

报告所有错误 error_report(E_ALL)

提供对未捕获的异常, 错误的全局处理 set_error_handler, set_exception_handler, register_shutdown_function

4. 外观注册 \Illuminate\Foundation\Bootstrap\RegisterFacades::class

app.aliases 中读取外观配置数组

'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class,
'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
'Bus' => Illuminate\Support\Facades\Bus::class,
'Cache' => Illuminate\Support\Facades\Cache::class,
'Config' => Illuminate\Support\Facades\Config::class,
'Cookie' => Illuminate\Support\Facades\Cookie::class,
'Crypt' => Illuminate\Support\Facades\Crypt::class,
'DB' => Illuminate\Support\Facades\DB::class,
'Eloquent' => Illuminate\Database\Eloquent\Model::class,
'Event' => Illuminate\Support\Facades\Event::class,
'File' => Illuminate\Support\Facades\File::class,
'Gate' => Illuminate\Support\Facades\Gate::class,
'Hash' => Illuminate\Support\Facades\Hash::class,
'Lang' => Illuminate\Support\Facades\Lang::class,
'Log' => Illuminate\Support\Facades\Log::class,
'Mail' => Illuminate\Support\Facades\Mail::class,
'Notification' => Illuminate\Support\Facades\Notification::class,
'Password' => Illuminate\Support\Facades\Password::class,
'Queue' => Illuminate\Support\Facades\Queue::class,
'Redirect' => Illuminate\Support\Facades\Redirect::class,
'Redis' => Illuminate\Support\Facades\Redis::class,
'Request' => Illuminate\Support\Facades\Request::class,
'Response' => Illuminate\Support\Facades\Response::class,
'Route' => Illuminate\Support\Facades\Route::class,
'Schema' => Illuminate\Support\Facades\Schema::class,
'Session' => Illuminate\Support\Facades\Session::class,
'Storage' => Illuminate\Support\Facades\Storage::class,
'URL' => Illuminate\Support\Facades\URL::class,
'Validator' => Illuminate\Support\Facades\Validator::class,
'View' => Illuminate\Support\Facades\View::class, ],

使用 spl_autoload_register(...) 处理类加载, 配合 class_alias() 提供类的别名调用

Facade外观类基类依赖__callStatic` 调用方法( 使用服务容器实例化对应类)

5. 服务提供者注册 \Illuminate\Foundation\Bootstrap\RegisterProviders::class

app.providers 中读取所有服务提供者

'providers' => [

        /*
* Laravel Framework Service Providers...
*/
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
Illuminate\Cookie\CookieServiceProvider::class,
Illuminate\Database\DatabaseServiceProvider::class,
Illuminate\Encryption\EncryptionServiceProvider::class,
Illuminate\Filesystem\FilesystemServiceProvider::class,
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
Illuminate\Hashing\HashServiceProvider::class,
Illuminate\Mail\MailServiceProvider::class,
Illuminate\Notifications\NotificationServiceProvider::class,
Illuminate\Pagination\PaginationServiceProvider::class,
Illuminate\Pipeline\PipelineServiceProvider::class,
Illuminate\Queue\QueueServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class,
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class, /*
* Package Service Providers...
*/ /*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
// App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class, # 路由表生成
],

服务提供者经过解析后分为 3 种类型的服务提供者:

  • eager 类型

    马上调用 register 注册

  • deferred 类型

    记录下来, 当服务容器解析对应服务时, 才注册对应的服务提供者

  • when 类型

    记录下来, 当对应 event 触发时在注册对应服务提供者

6. 启动提供者 \Illuminate\Foundation\Bootstrap\BootProviders::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);
};
}

路由表存储结构说明

Illuminate\Routing\Route 存储单条路由

Illuminate\Routing\RouteCollection 保存所有 Route 实例, 形成路由表

Illuminate\Routing\Router 类实例持有 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 Events\RouteMatched($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()
);
});
}

routerun() 方法最终将请求转给 Illuminate\Routing\ControllerDispatcher::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 \Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*/
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)

该过程是在 Symfony\Component\HttpFoundation\Response::prepare() 中进行

对响应的封装是通过 Illuminate\Http\Response 类完成, 该类底层是 Symfony 框架的 Response 类

即, Symfony\Component\HttpFoundation\Response

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();

Symfony\Component\HttpFoundation\Response

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);
}
}

[原创] Laravel 启动流程的更多相关文章

  1. MyCat源码分析系列之——配置信息和启动流程

    更多MyCat源码分析,请戳MyCat源码分析系列 MyCat配置信息 除了一些默认的配置参数,大多数的MyCat配置信息是通过读取若干.xml/.properties文件获取的,主要包括: 1)se ...

  2. Centos 6启动流程详解

    author:JevonWei 版权声明:原创作品 Centos6 启动流程 POST开机自检 当按下电源键后,会启动ROM芯片中的CMOS程序检查CPU.内存等硬件设备是否正常运行,CMOS中的程序 ...

  3. 一张图理清ASP.NET Core启动流程

    1. 引言 对于ASP.NET Core应用程序来说,我们要记住非常重要的一点是:其本质上是一个独立的控制台应用,它并不是必需在IIS内部托管且并不需要IIS来启动运行(而这正是ASP.NET Cor ...

  4. 插件占坑,四大组件动态注册前奏(二) 系统Service的启动流程

    转载请注明出处:http://blog.csdn.net/hejjunlin/article/details/52203903 前言:为什么要了解系统Activity,Service,BroadCas ...

  5. Spring基础系列-容器启动流程(1)

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9870339.html 概述 ​ 我说的容器启动流程涉及两种情况,SSM开发模式和Spri ...

  6. Spring基础系列-容器启动流程(2)

    原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9503210.html 一.概述 这里是Springboot项目启动大概流程,区别于SSM ...

  7. 《转》深入理解Activity启动流程(四)–Activity Task的调度算法

    本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启 ...

  8. 《转》深入理解Activity启动流程(三)–Activity启动的详细流程2

    本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启 ...

  9. 《转》深入理解Activity启动流程(三)–Activity启动的详细流程1

    本文原创作者:Cloud Chou. 出处:本文链接 本系列博客将详细阐述Activity的启动流程,这些博客基于Cm 10.1源码研究. 深入理解Activity启动流程(一)--Activity启 ...

随机推荐

  1. 14-python登入教务网(python+bs4)

    用request先得到到session对象,用其去放送请求,会自动保存cookie. 模拟有验证码的登入步骤: 1.发送请求登入页面: 2.分析验证码的地址,以及要将登入请求发往的地址(可以先输入错的 ...

  2. Maven常用配置

    运行mvn install时跳过Test 方法一: <project> [...] <build> <plugins> <plugin> <gro ...

  3. 手动添加ceph的mds

    1.在需要安装的目标机器上创建mds目录 mkdir -p / 2.生成mds的keyring,并将其写入/var/lib/ceph/mds/ceph-0/keyring文件中 ceph auth g ...

  4. php eval

    // Our PHP code inside a variable $phpCode = ' class Foo { private $name; public function __construc ...

  5. java修饰符 protect public protected

    1.private修饰词,表示成员是私有的,只有自身可以访问: 2.protected,表示受保护权限,体现在继承,即子类可以访问父类受保护成员(子类是可以访问父类的带protected修饰符的成员的 ...

  6. git 只merge一个commit的方法

    https://git-scm.com/book/tr/v2/Git-Basics-Viewing-the-Commit-History gil log 来查看commit的记录 Other main ...

  7. SQL server 累加求和

    1. SELECT SalesOrderID, ProductID, OrderQty    ,SUM(OrderQty) OVER(PARTITION BY SalesOrderID) AS Tot ...

  8. CodeForces 343D water tree(树链剖分)

    Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a res ...

  9. MongoDB YAML格式的配置文件

    根据官网的提示内容,默认的配置文件内容为 systemLog: verbosity: 0 quiet: false # traceAllExceptions: <boolean> sysl ...

  10. Windows下Mongodb安装及配置(转载)

    转载(https://blog.csdn.net/liang377122210/article/details/79062681) MongoDB的安装很简单,设置好安装路径后,一直Next直到安装结 ...