Home > php教程 > PHP开发 > body text

Analysis on the Session write failure problem caused by extending Laravel's default Session middleware

高洛峰
Release: 2016-12-27 10:04:12
Original
1073 people have browsed it

Due to project development needs recently, the mobile client and web page use a unified set of interfaces. In order to ensure that the session can be normal and compatible under various circumstances, I hope to change the way to obtain the SessionID. By default, all websites are implemented through the Cookie in the Header header of the HTTP request, and are associated with the corresponding data on the server side through the SessionID specified in the Cookie 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 In the 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 came. . .

After modification, push it to the branch. Before merging 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. The Token we provide 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 I modified the middleware code I created into the inherited middleware code. Consistency doesn't help either, but strangely, after I switch the middleware back to the original middleware I don't have this problem.

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 the value is false, then Will cause our previous situation. The key is that when the 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 generally lies in 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, resulting in the previous attributes is initialized.

Then the solution is obvious, make it a singleton.

I added the following line of code in the register method of app/Providers/AppServiceProvider.php, which solved the previous problem:

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

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

For more related articles on the analysis of Session write failure caused by extending Laravel’s default Session middleware, please pay attention to the PHP Chinese website!

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 Recommendations
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template