web-dev-qa-db-ja.com

EventSubscriberで検証用のCookieが見つかりません

このモジュールがあります Splash Redirect ここで、src/EventSubscriber/SplashRedirectEventSubscriber.phpはCookie $config_cookieが存在するかどうかを確認することになっています。すでに存在する場合、ユーザーは要求されたノード($config_source)が存在する場合notが存在する場合、ユーザーは$config_destinationに送信され、Cookie($config_cookie)。

$config_cookieの作成と$config_destinationへのリダイレクトは成功しますが、一度作成されたCookieの存在を確認することはなく、ユーザーを$config_destinationにリダイレクトし続けます。

手がかりはありますか? Drupal 8.6

<?php

namespace Drupal\splash_redirect\EventSubscriber;

use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Drupal\Core\Routing\TrustedRedirectResponse;

/**
 * Splash redirect Event Subscriber.
 */
class SplashRedirectEventSubscriber implements EventSubscriberInterface {

  /**
   * Triggered when system sends response.
   */
  public function modifyIntercept(GetResponseEvent $event) {
    $config = \Drupal::config('splash_redirect.settings');
    $config_enabled = $config->get('splash_redirect.is_enabled');
    $config_source = $config->get('splash_redirect.source');
    $config_destination = $config->get('splash_redirect.destination');
    $config_cookie = $config->get('splash_redirect.cookie_name');
    $config_duration = $config->get('splash_redirect.duration');

    // If splash config is not enabled then we don't need to do any of this.
    if ($config_enabled == 1) {
      // Current request from client.
      $request = \Drupal::request();
      $current_uri = $request->getRequestUri();
      $http_Host = $request->getHost();
      // Current response from system.
      $response = $event->getResponse();
      $route = (\Drupal::routeMatch()->getParameter('node')) ? \Drupal::routeMatch()->getParameter('node')->id() : null;
      $has_cookie = $request->cookies->has($config_cookie);

      // If splash-cookie has not been set, and user requesting 'source' page,
      // set cookie and redirect to splash page.
      if ($config_source == $route) {
        // Kill cache on this route or else cookie might not be read with VCL.
        \Drupal::service('page_cache_kill_switch')->trigger();

        if (!$has_cookie) {
          // Set redirect response with cookie and redirect location.
          $redir = new TrustedRedirectResponse($config_destination, '302');
          $cookie = new Cookie($config_cookie, 'true', strtotime('now + ' . $config_duration . 'days'), '/', '.' . $http_Host, false, true);
          $redir->headers->setCookie($cookie);
          $redir->headers->set('Cache-Control', 'public, max-age=0');
          $redir->addCacheableDependency($config_destination);
          $event->setResponse($redir);
        }
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    // Listen for response event from system and intercept.
    $events[KernelEvents::REQUEST][] = ['modifyIntercept'];
    return $events;
  }

}
5
Kris Robinson

いくつかのアイデア:

設定と同様に、Cookieのキャッシュ依存関係も追加する必要があります。

  $response->getCacheableMetadata()->addCacheContexts(['cookies:' . $config_cookie]);

または、キャッシュできないRedirectResponseを使用して物事を簡略化します。

また、コードが32を持つルーティングにのみ依存するため、イベントサブスクライバーの優先度(31など)を設定してみてください。

  $events[KernelEvents::REQUEST][] = ['modifyIntercept', 31];

リクエストサブスクライバーではまだ応答がないため、応答を取得する必要はありません。代わりにリクエストを取得し、マスターリクエストであることを確認してください。したがって、これはサブスクライバーが最も頻繁に開始する方法です。

  public function onKernelRequest(GetResponseEvent $event) {
    if (!$event->isMasterRequest()) {
      return;
    }
    $request = $event->getRequest();
    ...

テストのためにもう少し単純化し、ダミー値を使用します:

  public function onKernelRequest(GetResponseEvent $event) {
    if (!$event->isMasterRequest()) {
      return;
    }
    $route_match = \Drupal::routeMatch();
    if (!$route_match->getRouteName() == 'entity.node.canonical') {
      return;
    }
    $request = $event->getRequest();
    if ($route_match->getRawParameter('node') == '1') {
      \Drupal::service('page_cache_kill_switch')->trigger();
      if (!$request->cookies->has('foo')) {
        $redirect = new RedirectResponse($request->getBasePath() . '/node/2', 302);
        $redirect->headers->setCookie(new Cookie('foo', '123', '+30 seconds'));
        $event->setResponse($redirect);
      }
    }
  }

これは私のローカル開発環境で動作しています。


完全なコード(依存関係の挿入を含む):

/ src/EventSubscriber/MymoduleSubscriber.php

<?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\Routing\RouteMatchInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Cookie;

/**
 * mymodule event subscriber.
 */
class MymoduleSubscriber implements EventSubscriberInterface {

  /**
   * The route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * Constructs event subscriber.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The route match.
   */
  public function __construct(RouteMatchInterface $route_match) {
    $this->routeMatch = $route_match;
  }

  /**
   * Kernel request event handler.
   *
   * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
   *   Response event.
   */
  public function onKernelRequest(GetResponseEvent $event) {
    if (!$event->isMasterRequest()) {
      return;
    }
    if (!$this->routeMatch->getRouteName() == 'entity.node.canonical') {
      return;
    }
    $request = $event->getRequest();
    if ($this->routeMatch->getRawParameter('node') == '1') {
      \Drupal::service('page_cache_kill_switch')->trigger();
      if (!$request->cookies->has('foo')) {
        $redirect = new RedirectResponse($request->getBasePath() .'/node/2', 302);
        $redirect->headers->setCookie(new Cookie('foo', '123', '+30 seconds'));
        $event->setResponse($redirect);
      }
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      KernelEvents::REQUEST => ['onKernelRequest', 31],
    ];
  }

}

mymodule.services.yml

services:
  mymodule.event_subscriber:
    class: Drupal\mymodule\EventSubscriber\MymoduleSubscriber
    arguments: ['@current_route_match']
    tags:
      - { name: event_subscriber }
6
4k4

オリジナル splash_redirect module dev here。キャッシングラビットホールにご参加いただきありがとうございます。 (申し訳ありませんが、まだ「コメント」を作成することはできませんので、これを回答に入れなければなりません)

素晴らしい提案をしてくれた@ 4k4のおかげで、次のリリースでそれらのいくつかを実装する可能性がありますが、OPの問題はVary: cookieヘッダーを設定し、ソースリダイレクトをキャッシュするPantheonのグローバルCDNに固有のようです。

*したがって、パンテオンでsplash_redirectを使用している場合、 スプラッシュCookie名の前に「SESS」を付けてください 、たとえばSESSsplash *

4
AdamB