Analysis of Middleware Source Code Based on laravel5.2

01-28-2024

In laravel5.2, the main function of Http is to filter Http requests (php aritsan has no middleware mechanism), and at the same time, it makes the hierarchy of the system (Http filtering layer) more clear and elegant to use. But the code to realize middleware is very complicated. Let's analyze the source code of middleware. Middleware source middleware itself is divided into two types, one is all http, and the other is for route. A Request cycle with middleware is: the request must go through the Http middleware before it can be Routed, and then through the Route middleware of the route corresponding to Requset, and finally it will enter the corresponding Controller code. Laravel divided the requests into two types: http and console. Different request methods use their own Kernel to drive Application. Http requests are driven by the class \ Illuminate \ Foundation \ HTTP \ Kernel, which defines all middleware, and its parent class \ Illuminate \ Foundation \ HTTP \ Kernel:: Handle is the entrance for processing requests.

Http middleware tracks the entry handle () method, and it is easy to find this function (\ illuminate \ foundation \ http \ kernel:: sendrequestthrouter):

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

Execution description: 1.$result_0 is the initialized value, which is $firstSlice, that is, the return callback of \ illuminate \ pipeline \ pipeline:: getInitial Slice 2. Every time an element is traversed, the callback of \ illuminate \ pipeline:: getSlice will be executed. At the same time, a callback will be returned. 3. The specific execution code in $ result is in getSlice (). 4. The final result of array_reduce is $result_3, which is a callback function with multiple closures. 5. Call _ user _ func ($ result _ 3, $ this-> passable) is executed, that is, the function ($ this-> passable) is executed.

At this point, it is clear how then () runs. To continue, we need to figure out how the callback function is executed. Now, follow the Pipeline in sendRequestThroughRouter to see how it is executed.

//Bring in specific parameters. return (new Pipeline($this->app)) ->send($request) ->through(['\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode']) ->then($this->dispatchToRouter());

Using the above analyzed Pipeline to execute the process, it will soon be analyzed that the last execution is

function($requset) use (\Illuminate\Foundation\Http\Kernel::dispatchToRouter(), '\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode') { if ($pipe instanceof Closure) { return call_user_func($pipe, $passable, $stack); } // $name and $parameters are easy to get. // $name = '\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode'; // $parameters = []; list($name, $parameters) = $this->parsePipeString($pipe); //What is executed is \ Illuminate \ Foundation \ HTTP \ Middleware \ CheckFormaintenanceMode:: Handle ($ request, \ Illuminate \ Foundation \ HTTP \ Kernel:: Dispatcher ()). return call_user_func_array([$this->container->make($name), $this->method], array_merge([$passable, $stack], $parameters)); }

The logical processing has reached \ Illuminate \ Foundation \ HTTP \ Middleware \ CheckFormainTenanceMode:: Handle, and its code is:

public function handle($request, Closure $next) { if ($this->app->isDownForMaintenance()) { throw new HttpException(503); } return $next($request); }

Here, it handles the conditions that this middleware needs to filter, and at the same time, it executes $next($Request), that is, \ illuminate \ foundation \ Http \ kernel:: dispatcher (), so that the request is transferred to the Router, and all the processing work of the HTTP middleware is completed. And $next($Request) is an indispensable operation for every middleware, because the callback is nested in the callback, that is, the middleware passes the request to the next callback, and it will be parsed to the next middleware until the last one. Follow closely the above analyzed Pipeline execution process, and talk about its completeness:

6. Execute the callback in $result_3, getSlice to instantiate the middleware, execute its handle, and execute the callback in the middleware processing.

7. Callbacks are nested in the callback, and each middleware needs the code $next($request) to execute the callback, so as to ensure that the callback in the callback will be executed. The order of execution is 3::handel, 2::handel, 1::handel, $first.

8. The innermost layer must be the parameter passed to then (), and then performs the last step.

9. The order of execution is from the last one in the array, forward to the parameter of then (). In order to make its execution order from the first one in the array to the last one, and then to the parameter in then (), an inverse array_reverse is made in the then () method.

Summary of Pipeline Now, all the execution processes of Pipeline have been analyzed. Implementing code is really winding, but it should be easy to write custom middleware after understanding it. Now translate the use of Pipeline into Chinese, which should be like this.

//Use the pipeline to send the $request through the middleware and then to the $func. (new Pipeline($this->app))->send($request)->through($this->middleware)->then($func);

This kind of code is elegant and high both semantically and in use! It's really high! Back to the source code, the process of Requset enters the Router through the dispatchToRouter.

Route Middleware In the Router, \ Illuminate \ Routing \ Router:: Dispatch undertakes the requset from the Http middleware, and the Router distributes the Request to the specific Route for further processing. The main code is as follows:

public function dispatchToRoute(Request $request) { //Find the specific routing object, and the process is short. $route = $this->findRoute($request); $request->setRouteResolver(function () use ($route) { return $route; }); //Execute the event that the Request matches the Route. The specific code is here: \ Illuminate \ Foundation \ Providers \ FoundationServiceProvider:: ConfigureFormRequests. $this->events->fire(new Events\RouteMatched($route, $request)); //This is where the routing middleware runs. $response = $this->runRouteWithinStack($route, $request); return $this->prepareResponse($request, $response); } protected function runRouteWithinStack(Route $route, Request $request) { //Get the middleware on this route. //Simply click to write: // $middleware = App::shouldSkipMiddleware() ? [] : $this->gatherRouteMiddlewares($route); $shouldSkipMiddleware = $this->container->bound('middleware.disable') && $this->container->make('middleware.disable') === true; $middleware = $shouldSkipMiddleware ? [] : $this->gatherRouteMiddlewares($route); //After understanding the Pipeline, it is easy to understand here. It should be through the pipeline, send a $request, go through $middleware, and then call back in Then. return (new Pipeline($this->container)) ->send($request) ->through($middleware) ->then(function ($request) use ($route) { return $this->prepareResponse( $request, $route->run($request) ); }); }

How to get the Route middleware, you can follow gatherRouteMiddlewares. This code is not difficult and easy to follow. Next, the Request will arrive. As for the Controller, it is not difficult for the code of how the request arrives at the controller, so I won't say it here.

After the middleware after the Controller successfully obtains the Response, it executes $ kernel-> terminate ($ request, $ response) in line public/index.php58; , that is, after the main logic processing is completed, execute this code. It actually calls Yes \ Illuminate \ Foundation \ http \ kernel:: terminate. It is easy to find that it has processed the middleware involved in this request and executed its own terminate method. Here, another function of middleware is displayed, that is, the finishing work after the main logic is completed. So far.

How to use middleware is clearly explained in the official documents.

At this point, the implementation logic and use of middleware are clear. From the order of execution, one is before the Controller and the other is after the Controller, so its very important function is to make the Controller focus on its main logic responsibilities more clearly. Strangely, the execution methods of the two middleware are different, \Illuminate\ Foundation \ http \ kernel:: terminate, middleware ends without Pipeline, but directly foreach. The same work is realized with two codes. Now, middleware itself is not complicated, but it brings me two inspirations: 1. Clear hierarchy 2. Elegance brought by pipeline.

Related recommendations:

An example of custom package development in laravel5.4

How to Create Custom Artisan Console Commands in Laravel 5.1 Framework

Analysis of startup process of laravel framework

Copyright Description:No reproduction without permission。

Knowledge sharing community for developers。

Let more developers benefit from it。

Help developers share knowledge through the Internet。

Follow us