Maison  >  Article  >  php教程  >  Analyse du problème d'échec d'écriture de session causé par l'extension du middleware de session par défaut de Laravel

Analyse du problème d'échec d'écriture de session causé par l'extension du middleware de session par défaut de Laravel

高洛峰
高洛峰original
2016-12-27 10:04:121073parcourir

En raison des besoins de développement du projet récemment, le client mobile et le client Web utilisent un ensemble d'interfaces unifiés. Afin de garantir que la session peut être normale et compatible dans diverses circonstances, j'espère changer la façon d'obtenir le SessionID. Par défaut, tous les sites Web sont implémentés via le cookie dans l'en-tête Header de la requête HTTP, et le SessionID spécifié dans le cookie est associé aux données correspondantes côté serveur pour implémenter la fonction de session.

Cependant, pour les clients mobiles, le cookie d'origine peut ne pas être pris en charge ou il peut être bloqué en fonction des besoins de la plate-forme. Le développement nécessite donc l'ajout d'un en-tête de requête X-Session-Token pour identifier le SessionID. Dans le framework Laravel, l'initialisation, la lecture et le démarrage de la session sont tous implémentés via le middleware IlluminateSessionMiddlewareStartSession. Ce middleware a une méthode clé getSession. Cette méthode consiste à obtenir le SessionId et à indiquer au composant Session quelles informations d'identification utiliser pour restaurer les données de session.

Ce middleware est enregistré sous le fichier app/Http/Kernel.php.

J'ai créé une nouvelle classe pour hériter du middleware et remplacé le lieu d'enregistrement sous app/Http/Kernel.php Le code source de la méthode getSession d'origine est le suivant :

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

In In. le nouveau middleware, je l'ai changé en :

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;
}

Mais des problèmes sont également survenus. . .

Après modification, poussez-le vers la branche. Avant de fusionner dans la branche principale de développement, vous devez souvent exécuter un test unitaire. Malheureusement, le cas qui a réussi avant a signalé une erreur cette fois. Le composant CSRF a signalé une erreur de jeton. Le jeton que nous fournissons ici n'est pas différent de l'habituel et le problème doit provenir de la session.

Il est à noter que lorsque je modifie le code du middleware, on peut dire que cela n'a aucun impact sur le framework. En fait, ce n'est pas le cas, car j'ai modifié le code du middleware que j'ai créé dans le framework. le code du middleware hérité n'aide pas non plus, mais étrangement, après avoir ramené le middleware au middleware d'origine, je n'ai pas ce problème.

J'ai donc exécuté le code dans des conditions normales et anormales, débogué avec des points d'arrêt aux points clés et découvert que le problème réside dans un attribut important du middleware, $sessionHandled. Si la valeur est fausse, alors Will. causer notre situation précédente. La clé est que lorsque le middleware est démarré, la méthode handle sera utilisée pour le middleware Session, la première ligne de code de la méthode handle est :

$this->sessionHandled = true;

Intéressant. . .

Nous le savons. La caractéristique du framework Laravel est son conteneur IoC, qui est chargé d'initialiser diverses classes dans le framework pour implémenter diverses injections de dépendances afin d'assurer un couplage lâche entre les composants. Le middleware ne fait certainement pas exception. Vous devez savoir que la plus grande différence entre un singleton et une instance ordinaire est que peu importe le nombre de fois qu'il est créé, le singleton sera toujours le même et les propriétés de l'instance ne seront pas initialisées. le middleware doit être un singleton, et celui que j'ai créé moi-même Middleware n'est qu'une instance d'une classe ordinaire. Mais pour savoir ce qui se passe et pourquoi, j'ai besoin de confirmer mon idée (en fait, j'ai déjà pensé à la solution, qui sera discutée plus tard).

Ensuite, le problème est à peu près l'initialisation du middleware, je dois donc me remonter le moral et regarder de plus près le code de démarrage de Laravel. Le point clé ici réside dans une classe appelée IlluminatePipelinePipeline.


Cette classe comporte trois méthodes importantes : envoyer, passer et ensuite. où est alors la clé qui démarre tout. Cette classe est principalement quelque chose qui exécute en continu plusieurs étapes de démarrage du framework. La première consiste à initialiser les composants requis pour le processus de traitement (Requête et middleware), et deuxièmement, à transmettre la requête à travers la pile composée de ces composants de traitement (un ensemble de composants de traitement). middleware et composants de répartition de routage), et renvoie enfin le résultat du traitement (Réponse).

On peut dire que cette chose est le cœur de la partie Http de Laravel (enfin, à l'origine, c'est le noyau). Ensuite, le problème précédent réside dans la méthode then de Pipeline et la méthode getSlice qu'il appelle. En observant directement la méthode getSlice, vous pouvez constater qu'elle est responsable de la génération de la pile de traitement et de l'instanciation de la classe Middleware. Le code complet de la méthode est le suivant :

Vous pouvez remarquer $this->container->make($name), ce qui signifie qu'il initialise une classe middleware, qui est simplement make. Si ce n'est pas un singleton, il l'utilisera à plusieurs reprises. new, ce qui entraîne l'initialisation des propriétés précédentes.
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));
}
};
};
}


Alors la solution est évidente, faites-en un singleton.

J'ai ajouté la ligne de code suivante dans la méthode de registre de app/Providers/AppServiceProvider.php, ce qui a résolu le problème précédent :

$this->app->singleton(SessionStart : class); // SessionStart est le nom de ma classe middleware

Ce qui précède vous présente l'analyse complète du problème d'échec d'écriture de session causé par l'extension du middleware de session par défaut de Laravel. J'espère que vous l'aimerez.

Pour plus d'articles connexes sur l'analyse du problème d'échec d'écriture de session causé par l'extension du middleware de session par défaut de Laravel, veuillez faire attention au site Web PHP chinois !

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn