Страница пришла из кэша nginx за 30 миллисекунд, а сетка товаров на ней появляется через две секунды. Потому что сетка — это блок, который страница догружает отдельным запросом. И для nginx этот запрос не кэшируется вообще.

Это первая часть цикла «Кэш фрагментов и Redis». Здесь — всё про блоки, которые страница догружает ajax-запросами: как держать их в кэше так же надёжно, как страницы. О кэше самих страниц — цикл «Кэш страниц без MISS».

Почему nginx не кэширует ajax-блоки

В WordPress блоки обычно грузятся через admin-ajax.php. Это POST-запрос, и WordPress отвечает на него с Cache-Control: no-store. Оба признака для nginx значат «не кэшировать». И правильно: через тот же адрес идут отправка форм, лайки, корзина.

Цена — каждый показ блока собирается заново:

  • сетка на 24 карточки — около 2 секунд;
  • переход на следующую страницу каталога — 2,2 секунды.

После того как у блоков появился свой кэш, переход на следующую страницу стал занимать 0,2 секунды.

Главный приём: чистая функция рендера

Чтобы блок можно было и отдать посетителю, и прогреть фоновым воркером, его сборка выносится в функцию, которая не знает ни про $_POST, ни про вывод:

/** Принимает параметры, возвращает готовую разметку. Без $_POST и echo. */
function grid_render_fragment(array $args): array {
    $q = new WP_Query([
        'post_type'      => 'product',
        'paged'          => (int) ($args['page'] ?? 1),
        'posts_per_page' => (int) ($args['count'] ?? 24),
        'tax_query'      => grid_tax_query($args),
    ]);
    ob_start();
    get_template_part('templates/grid', null, ['query' => $q]);
    return ['html' => ob_get_clean(), 'pages' => $q->max_num_pages];
}

// ajax: разобрать запрос, спросить кэш, при нужде — отрендерить
add_action('wp_ajax_nopriv_grid', 'grid_ajax');
add_action('wp_ajax_grid', 'grid_ajax');
function grid_ajax() {
    $args = grid_args_from_request($_POST);           // только разрешённые поля
    wp_send_json(frag_get_or_render('grid', $args, 'grid_render_fragment'));
}

Одна и та же функция работает и в ajax-запросе посетителя, и в фоновом воркере прогрева. Если рендер зависит от чего-то вне аргументов, воркер соберёт не то, что увидит посетитель, — несколько частей цикла именно об этом.

Что дальше

  • как устроено чтение «отдай старое, обнови фоном» и почему версии надо хранить в значении, а не в ключе;
  • что обязано входить в ключ блока;
  • как воркер травит кэш, если рендер не изолирован;
  • как собрать перечень ячеек автоматически и следить за полнотой;
  • и как перенести всё это из базы в Redis.

Индикатор. Статус блока отдаётся в заголовке ответа — у нас X-Frag-Cache: HIT, STALE, MISS или BYPASS. Без него ни одну из следующих частей не проверить.

Страница быстрая, а блоки на ней появляются медленно?

Пришлите адрес — проверю, кэшируются ли у вас ajax-блоки.

· полезно?
АЧ
Алексей Чикун веб-разработчик, команда TRIOHEAD

Делаю сайты и сервисы целиком: от вёрстки до сервера. Пишу о том, что проверил на своих проектах.

Комментарии

// загружаю комментарии…

Комментарии публикуются после проверки. Ссылки и HTML не принимаются.