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. 心理学轨迹及AI基础理论读后感

    今天简单的看了下心理学轨迹及AI基础理论发现世界确实是那3%的人改变的,我等屁民还努力在红尘中争渡,下面简单记录下我刚看完的思路,算做个笔记给自己看.. 模型建立的最终结果可以解读所有的心理学现象,可 ...

  2. 支付宝soa框架发展思路(转载)

    大家好,这里是首届QCon Beijing的现场,现在坐在我的旁边是的支付宝的首席架构师程立.先给大家介绍一下,支付宝架构发展到今天,经历哪些时期,都有哪些里程碑? 我回忆一下,支付宝系统架构发展大概 ...

  3. xgboost 里边的gain freq, cover

    assuming that you're using xgboost to fit boosted trees for binary classification. The importance ma ...

  4. linux进入单用户方法-乾颐堂

    RedHat7.2 在使用GRUB引导程序的时候如何进入单用户 1.在出现GURB引导画面时,按字母e,进入GRUB编辑状态 2在引导菜单后添加“1”或single,选定它,然后按字母b,就可引导到单 ...

  5. C++11新特性之auto

    auto的使用  c++11引入了auto类型说明符,auto让编译器通过初始值来推算变量的类型,所以auto定义的变量必须有初始值.  使用auto也能在一条语句中声明多个变量,因为一条声明语句只能 ...

  6. javascript总结28 :匿名函数

    1 匿名函数 //匿名函数. // (function (){ // console.log(1); // }) 2  匿名函数作用 //1.直接调用 (function (){ console.lo ...

  7. HDU 4514 湫湫系列故事――设计风景线 (树形DP)

    题意:略. 析:首先先判环,如果有环直接输出,用并查集就好,如果没有环,那么就是一棵树,然后最长的就是树的直径,这个题注意少开内存,容易超内存, 还有用C++交用的少一些,我用G++交的卡在32764 ...

  8. form action 相对路径出问题

    http://www.w3chtml.com/html5/tag/base.html <base> 标签为页面上的所有链接规定默认地址或默认目标. 通常情况下,浏览器会从当前文档的 URL ...

  9. Debug 时,执行语句

    Display View The Display View displays the result of evaluating an expression in the context of the ...

  10. .NET基础 (02).NET运行机制

    .NET运行机制1 .NET程序被编译成什么形式的代码2 JIT是如何工作的3 简述程序集的加载机制4 如何配置程序集的版本策略 1 .NET程序被编译成什么形式的代码 .NET程序在编写完成后,会经 ...