Рейтинг:2

Отладка заголовка "UNCACHEABLE"

флаг in

У нас есть сайт, домашняя страница которого не кэшируется и содержит заголовки:

x-кеш: МИСС, МИСС
х-кэш-попаданий: 0, 0
x-content-type-options: nosniff
x-drupal-динамический-кеш: UNCACHEABLE

Я сузил это до содержимого областей контента и отключил «Контент главной страницы» для главной страницы. Затем это дало мне кеш HIT и больше не отвечало как UNCACHEABLE.Оттуда я сузил его до средства форматирования полей, используемого в абзаце. У нас есть пользовательский, который расширяет обычный форматировщик рендеринга объектов.

Если я поменяю его обратно на исходный форматтер «Render entity», все будет в порядке. Итак, это должно быть что-то, что мы делаем в этом пользовательском форматере, вызывающем проблему.

Когда я следую за xdebug, я вижу, что shouldCacheResponse из DynamicPageCacheSubscriber возвращает FALSE, потому что что-то устанавливает max-age в 0 (не по коду). Похоже, что вызовы addCacheableDependency могут вызывать такое поведение в форматере:

По сути, средство форматирования добавляет данные кеша в рендеринг, поэтому, если какой-либо из его элементов, на которые он ссылается, обновляется, кеш должен быть признан недействительным для этого абзаца хоста, чтобы он повторно рендерил:

     $view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity->getEntityTypeId());
      $elements[$delta] = $view_builder->view($entity, $view_mode, $entity->language()->getId());

      пытаться {
        $parent = $items->getParent();
        $parent_entity = $parent->getValue();
        $elements[$delta]['#cache']['keys'][] = $parent_entity->id();
        $elements[$delta]['#cache']['keys'][] = $parent_entity->bundle();
        $elements[$delta]['#cache']['keys'][] = $parent_entity->getEntityTypeId();
        $elements[$delta]['#cache']['keys'][] = 'delta_' . $ дельта;
        $elements[$delta]['#cache']['keys'][] = 'context_aware';

        $this->renderer->addCacheableDependency($elements[$delta], $parent);

        если ($entity->hasField('field_author')) {
          $child = $entity->field_author->entity;

          если (isset($child)) {
            $this->renderer->addCacheableDependency($elements[$delta], $child);
          }
        }

        // аналогичные операторы с addCacheableDependency

Если я прокомментирую эту начальную строку:

$this->renderer->addCacheableDependency($elements[$delta], $parent);

Затем я получаю кешируемый ответ.Похоже, это связано с тем, что элемент $parent (даже если это узел, абзац или медиаобъект) вызывает это:

  /**
   * Создает объект CacheableMetadata из зависимого объекта.
   *
   * @param \Drupal\Core\Cache\CacheableDependencyInterface|смешанный объект $
   * Объект, метаданные кэшируемости которого необходимо получить. Если он реализует
   * CacheableDependencyInterface, будут использоваться его метаданные кешируемости,
   * в противном случае переданный объект должен считаться некэшируемым, поэтому
   * установлен максимальный возраст 0.
   *
   * @return статический
   */
  общедоступная статическая функция createFromObject($object) {
    if ($object instanceof CacheableDependencyInterface) {
      $мета = новый статический();
      $meta->cacheContexts = $object->getCacheContexts();
      $meta->cacheTags = $object->getCacheTags();
      $meta->cacheMaxAge = $object->getCacheMaxAge();
      вернуть $мета;
    }

    // Объекты, которые не реализуют CacheableDependencyInterface, должны считаться
    // быть некэшируемым, поэтому установите max-age 0.
    $мета = новый статический();
    $meta->cacheMaxAge = 0;
    вернуть $мета;
  }

Установка для cacheMaxAge значения 0, поскольку это не экземпляр CacheableDependencyInterface.

Если я уже устанавливаю ключи кеша, нужна ли эта строка:

$this->renderer->addCacheableDependency($elements[$delta], $parent);

Если я уберу это, будет ли неблагоприятный эффект (например, рендеринг не будет выполнять повторный рендеринг при сохранении ссылочных элементов)?

4uk4 avatar
флаг cn
Установить ключи кеша недостаточно, вам также нужны теги кеша. Так что не удаляйте эту строку, просто проверьте, что объект не NULL.
sonfd avatar
флаг in
Да, ключи кеша на самом деле ничего не делают - контексты, теги и максимальный возраст - это то, что вы хотели бы сохранить.
Kevin avatar
флаг in
$parent не равен нулю, но получен в createFromObject как экземпляр EntityAdapter (содержащий узел сущности или абзац), который я не могу отследить как реализующий CacheableDependencyInterface
4uk4 avatar
флаг cn
ОК, теперь я вижу проблему, объект с данными кэша — $parent_entity.
Kevin avatar
флаг in
Я так и подозревал, спасибо за подтверждение. Изменение этого возвращает кэшируемый ответ в браузер.
Рейтинг:4
флаг in

Это было хорошее глубокое погружение в отладку. Как уже упоминал 4к4 проблема первая addCacheableDependency линия.

Вместо того, чтобы передавать сам объект хоста, я по ошибке передавал объект, возвращенный из получитьродитель который является Типизированные данные экземпляр, который не реализует CacheableDependencyInterface - таким образом, максимальный возраст устанавливается равным 0, а НЕКЭШИРУЕМЫЙ результат заголовка.

Передача сущности (возвращенной из получить значение ()) решил проблему:

    $parent = $items->getParent();
    $parent_entity = $parent->getValue();
    ...
    $this->renderer->addCacheableDependency($elements[$delta], $parent_entity);

Ответить или комментировать

Большинство людей не понимают, что склонность к познанию нового открывает путь к обучению и улучшает межличностные связи. В исследованиях Элисон, например, хотя люди могли точно вспомнить, сколько вопросов было задано в их разговорах, они не чувствовали интуитивно связи между вопросами и симпатиями. В четырех исследованиях, в которых участники сами участвовали в разговорах или читали стенограммы чужих разговоров, люди, как правило, не осознавали, что задаваемый вопрос повлияет — или повлиял — на уровень дружбы между собеседниками.