Home > Backend Development > PHP Tutorial > Analysis of the Session write failure problem caused by extending Laravel's default Session middleware, laravelsession_PHP tutorial

Analysis of the Session write failure problem caused by extending Laravel's default Session middleware, laravelsession_PHP tutorial

WBOY
Release: 2016-07-12 09:01:07
Original
1101 people have browsed it

About analysis of the Session write failure problem caused by extending Laravel's default Session middleware, laravelsession

Recently due to project development needs, the mobile client and web page use a unified set of interfaces. In order to ensure that the session can work normally and be compatible under various circumstances, I hope to change the method of obtaining the SessionID. By default, all websites are implemented through the Cookie in the Header header of the HTTP request, and the SessionID specified in the Cookie is associated with the corresponding data on the server side to implement the session function.

However, for mobile clients, the original Cookie may not be supported, or it may be blocked according to platform needs, so development requires adding a request header X-Session-Token to identify the SessionID. In the Laravel framework, Session initialization, reading and starting are all implemented through the IlluminateSessionMiddlewareStartSession middleware. This middleware has a key method getSession. This method is to obtain the SessionId and tell the Session component what credentials to use to restore the Session data.

This middleware is registered under the app/Http/Kernel.php file.

I created a new class to inherit the middleware and replaced the registration place under app/Http/Kernel.php. The original getSession method source code is as follows:

public function getSession(Request $request)
{
$session = $this->manager->driver();
$session->setId($request->cookies->get($session->getName()));
return $session;
}
Copy after login

In the new middleware, I changed it to:

public function getSession(Request $request)
{
$session = $this->manager->driver();
// 判断是否是接口访问并根据实际情况选择 SessionID 的获取方式
if ($request->headers->has('x-session-token')) {
$sessionId = $request->headers->has('x-session-token');
} else {
$sessionId = $request->cookies->get($session->getName());
}
$session->setId($sessionId);
return $session;
}

Copy after login

But trouble also comes. . .

After modification, push it to the branch. Before merging it into the main development branch, you often need to run a unit test. Unfortunately, the Case that passed before reported an error this time. The problem is that the CSRF component reported a Token error, and we are in The Token provided here is no different from usual, and the problem must be with the Session.

It is worth noting that when I modify the middleware code, it can be said that it has no impact on the framework at all. In fact, it does not, because it does not help if I modify the middleware code I created to be consistent with the inherited middleware code. , but strangely, this problem does not occur after I change the middleware back to the original middleware.

So I ran the code under normal conditions and abnormal conditions, debugged with breakpoints at key points, and found that the problem lies in an important attribute of the middleware $sessionHandled. If this value is false, it will cause us previous situation. The key is that when middleware is started, the handle method will be used. For the Session middleware, the first line of code of the handle method is:

$this->sessionHandled = true;

Interesting. . .

We know. The characteristic of the Laravel framework is its IoC container, which is responsible for initializing various classes in the framework to implement various dependency injections to ensure loose coupling between components. Middleware is certainly no exception. You must know that the biggest difference between a singleton and an ordinary instance is that no matter how many times it is created, the singleton will always be the same, and the properties in the instance will not be initialized. Therefore, the problem-free middleware must be a singleton, and the one I created myself Middleware is just an instance of an ordinary class. But in order to know what is happening and why, I need to confirm my idea (in fact, I have already thought of the solution, which will be discussed later).

Then the problem is roughly the initialization of the middleware, so I have to cheer up and take a closer look at Laravel's startup code. The key point here lies in a class called IlluminatePipelinePipeline.

This class has three important methods send, through and then. where then is the key that starts everything. This class is mainly a thing that continuously executes several framework startup steps. The first is to initialize the components required for the processing process (Request and middleware), and secondly to pass the request through the stack composed of these processing components (a bunch of middleware and routing dispatch components). ), and finally returns the processing result (Response).

It can be said that this thing is the core of Laravel Http part (well, originally it is Kernel). Then the previous problem lies in Pipeline's then method and the getSlice method it calls. Directly observing the getSlice method, you can find that it is responsible for generating the processing stack and instantiating the Middleware class. The entire method code is as follows:

protected function getSlice()
{
return function ($stack, $pipe) {
return function ($passable) use ($stack, $pipe) {
if ($pipe instanceof Closure) {
return call_user_func($pipe, $passable, $stack);
} else {
list($name, $parameters) = $this->parsePipeString($pipe);
return call_user_func_array([$this->container->make($name), $this->method],
array_merge([$passable, $stack], $parameters));
}
};
};
}
Copy after login

You can notice $this->container->make($name), which means that it initializes a middleware class, which is simply make. If it is not a singleton, it will repeatedly use new, causing the previous attributes to be initialization.

Then the solution is obvious, make it a singleton.

I solved the previous problem by adding the following line of code to the register method of app/Providers/AppServiceProvider.php:

$this->app->singleton(SessionStart::class); // SessionStart is the name of my middleware class

The above introduces you to the entire analysis of the Session write failure problem caused by extending Laravel's default Session middleware. I hope you like it.

Articles you may be interested in:

  • Client-side solution to invalid Session object
  • Asynchronous HttpContext.Current implementation value method (solve asynchronous Application, Session, Cache ...and other invalid problems)
  • Multiple solutions to the problem of session invalidation by closing the browser
  • Solutions to iframe cross-domain and session invalidation problems
  • Laravel 5 Framework Learning Eloquent (laravel's ORM)
  • Laravel 5 Framework Learning Form
  • Laravel 5 Framework Learning Date, Mutator and Scope
  • Laravel 5 Framework Learning Form Verification
  • Laravel 5 Framework Learning Eloquent Relationship
  • Laravel 5 Framework Learning User Authentication
  • Laravel 5 Framework Getting Started (1)

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/1089945.htmlTechArticleAbout analysis of the Session write failure problem caused by extending Laravel’s default Session middleware, laravelsession has recently been replaced by mobile phones due to project development needs The client and web page use the same set...
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template