Interpretation of laravel kernel — HTTP kernel

Time:2021-1-28

Http Kernel

HTTP kernel is used in laravel to concatenate the core components of the framework for network request, simply speaking, as long as it is through thepublic/index.phpTo start the framework, you will use HTTP kernel, while others will use HTTP kernelartisanThe console kernel is used for processing commands, scheduled tasks, and queue start frameworks. Today, let’s sort out what HTTP kernel does.

Kernel binding

Since HTTP kernel is used to connect all parts of the framework in laravel to process network requests, let’s see how the kernel is loaded into the application instance of laravelpublic/index.phpWe’ll see it in the middle, and it’ll pass firstbootstrap/app.phpThis file is used to initialize the application

Here’s what’s going onbootstrap/app.phpThe code contains two main partsCreate application instanceandBind kernel to app service container

<?php
//The first part: create application instance
$app = new Illuminate\Foundation\Application(
    realpath(__DIR__.'/../')
);

//The second part: complete the kernel binding
$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
);

return $app;

The HTTP kernel inherits from the illuminatefoundationhttpkernel class. In the HTTP kernel, it defines the middleware related array. The middleware provides a convenient mechanism to filter the HTTP requests entering the application and process the HTTP responses leaving the application.

<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    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,
    ];
    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];
    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    ];
}

An array of bootstrappers with the property “bootstrappers” is defined in its parent class “illuminatefoundationhttpkernel”:

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,
];

The bootstrapper group includes six bootstrappers: environment detection, configuration loading, exception handling, facades registration, service provider registration and service startup.

For the explanation of middleware and bootloader, please refer to our previous chapters.

Application analysis kernel

After binding the HTTP kernel to the service container of the application in the application initialization phase, nextpublic/index.phpWe can see that the service container is usedmakeMethod to parse the HTTP kernel instance

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

When instantiating the kernel, the middleware defined in the HTTP kernel is registered with theRouterAfter registration, you can call the middleware that is applied on the route to achieve the purpose of filtering request before processing the HTTP request.

namespace Illuminate\Foundation\Http;
...
class Kernel implements KernelContract
{
    /**
     * Create a new HTTP kernel instance.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @param  \Illuminate\Routing\Router  $router
     * @return void
     */
    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);
        }
    }
}

namespace Illuminate/Routing;
class Router implements RegistrarContract, BindingRegistrar
{
    /**
     * Register a group of middleware.
     *
     * @param  string  $name
     * @param  array  $middleware
     * @return $this
     */
    public function middlewareGroup($name, array $middleware)
    {
        $this->middlewareGroups[$name] = $middleware;

        return $this;
    }
    
    /**
     * Register a short-hand name for a middleware.
     *
     * @param  string  $name
     * @param  string  $class
     * @return $this
     */
    public function aliasMiddleware($name, $class)
    {
        $this->middleware[$name] = $class;

        return $this;
    }
}

Processing HTTP requests

After creating the HTTP kernel instance through service parsing, you can use the HTTP kernel instance to process HTTP requests

//public/index.php
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

The request is processed throughIlluminate\Http\RequestOfcapture()Method creates a laravel request instance based on the information of the HTTP request entering the application, which will be used in the remaining life cycle of the subsequent applicationRequestThe request instance is the abstraction of this HTTP requestLaravel request instanceYou can refer to the previous chapters for the explanation of.

Abstracting HTTP requests intoLaravel request instanceAfter that, the request instance will be transmitted to the HTTP kernelhandleMethod, the request is processed by thehandleMethod.

namespace Illuminate\Foundation\Http;

class Kernel implements KernelContract
{
    /**
     * Handle an incoming HTTP request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    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;
    }
}

handleMethod receives a request object and generates a response object. actuallyhandleMethods we have been very familiar with it. When we explain many modules, we take it as the starting point, and gradually go deep into the interior of the module to explain the logic in the modulesendRequestThroughRouterMethod is mentioned by both the service provider and middleware. It loads the bootloader defined in the kernel to boot the application, and then uses thePipelineObject transfers HTTP request. The object flows through the HTTP middleware and routing middleware defined in the framework to complete the filtering request. Finally, the request is passed to the handler (controller method or closure in the route), and the handler returns the corresponding response. abouthandleFor the annotation of the method, I directly refer to the explanation in the previous chapter and put it here. For more detailed analysis, please see how to boot the application and how to transfer the data through various middleware to the handlerService providermiddleware alsorouteThere are three chapters.

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());
}
    
/*Booting the laravel application
1. Detectenvironment
2. Loadconfiguration loading application configuration
3. Configure logging
4. Handleexception registers the handler for exception handling
5. Register facades 
6. Register providers 
7. Bootproviders start providers
*/
public function bootstrap()
{
    if (! $this->app->hasBeenBootstrapped()) {
    /**Execute the bootstrap() function of each bootstrapper in $bootstrappers in turn
        $bootstrappers = [
             'Illuminate\Foundation\Bootstrap\DetectEnvironment',
             'Illuminate\Foundation\Bootstrap\LoadConfiguration',
             'Illuminate\Foundation\Bootstrap\ConfigureLogging',
             'Illuminate\Foundation\Bootstrap\HandleExceptions',
             'Illuminate\Foundation\Bootstrap\RegisterFacades',
             'Illuminate\Foundation\Bootstrap\RegisterProviders',
             'Illuminate\Foundation\Bootstrap\BootProviders',
            ];*/
            $this->app->bootstrapWith($this->bootstrappers());
    }
}

Send response

After the above stages, we finally get the response to return, and then we send the response.

//public/index.php
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);

//Send response
$response->send();

Send response byIlluminate\Http\ResponseOfsend()Method completes the parent class, which is defined in the parent classSymfony\Component\HttpFoundation\ResponseIn the middle.

public function send()
{
    $this - > sendheaders(); // send response header information
    $this - > sendcontent(); // send message subject

    if (function_exists('fastcgi_finish_request')) {
        fastcgi_finish_request();
    } elseif (!\in_array(PHP_SAPI, array('cli', 'phpdbg'), true)) {
        static::closeOutputBuffers(0, true);
    }
    return $this;
}

For a detailed analysis of the response object, please refer to the previous chapter on the laravel response object.

Terminate application

After the response is sent, the HTTP kernel calls theterminableMiddleware does some follow-up work. For example, laravel’s built-in “session” middleware will write the session data to the memory after the response is sent to the browser.

// public/index.php
//Termination of proceedings
$kernel->terminate($request, $response);
//Illuminate\Foundation\Http\Kernel
public function terminate($request, $response)
{
    $this->terminateMiddleware($request, $response);
    $this->app->terminate();
}

//Terminate Middleware
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, $parameters) = $this->parseMiddleware($middleware);
        $instance = $this->app->make($name);
        if (method_exists($instance, 'terminate')) {
            $instance->terminate($request, $response);
        }
    }
}

Implementation of HTTP kernelterminateMethod is calledteminableMiddlewareterminateMethod, after the call is completed, the life cycle of the whole application from the HTTP request to the response is over.

summary

The HTTP kernel described in this section mainly plays the role of concatenation, in which the designed initialization application, the boot application, the HTTP request abstracted into a request object, the request object passed to the handler through the middleware, the response generated and sent to the client. These things have been mentioned in the previous chapters, and there is nothing new. I hope that through this article, we can string each point mentioned in the previous article into a line, so that we can have a clearer concept of how laravel works as a whole.

This article has been included in a series of articlesLaravel source learningIn.

Welcome to my official account, Bi. I’m preparing to share some technical knowledge learned and summarized in my daily work, and I will also share some knowledge and learning methods.

Interpretation of laravel kernel -- HTTP kernel