Укажите в Vary названия заголовков запроса, по которым сервер выбирает представление публичной страницы. На Mac проверяйте по одному заголовку за раз, сравнивайте возвращаемый документ и метаданные и проверяйте ответ по умолчанию до изменения конфигурации.

Это руководство предназначено для тех, кто поддерживает общедоступный документ и проверяет его доставку из Терминала Mac. В качестве примера используется синтетическое руководство «Фигуры», доступное по одному URL в формате HTML или обычного текста. Задача — определить фактические входные данные выбора, настроить соответствующий заголовок ответа и проверить результат.

Что указывать в заголовке Vary страницы?

Vary указывает поля запроса, которые могут влиять на выбор представления помимо метода запроса и целевого URL. В его значениях указываются названия заголовков, например Accept, а не запрошенные типы медиа. Он описывает поведение выбора; добавление этого заголовка само по себе такое поведение не реализует. RFC 9110: семантика HTTP, раздел 12.5.5.

Например, если сервер выбирает HTML или обычный текст по Accept, соответствующее поле ответа — Vary: Accept. Если уровень доставки также выбирает сжатый или несжатый вариант по Accept-Encoding, сохраните и это измерение: Vary: Accept, Accept-Encoding. Это условные примеры, а не универсальная конфигурация для любой страницы. Согласование содержимого.

Практический вопрос таков: может ли кэшированный ответ, выбранный для одного запроса, оказаться неподходящим для другого из-за изменения этого заголовка? Правила кэширования HTTP требуют совпадения указанных полей перед повторным использованием без повторной проверки. Отсутствующее указанное поле совпадает с другим отсутствующим полем, но не с присутствующим. RFC 9111: кэширование HTTP, раздел 4.1.

Для начала составьте перечень условий выбора. Проверьте правила приложения по выбору документа и все преобразования ответа, применяемые после этого. Различающийся результат — полезное свидетельство, но одинаковый результат для двух запросов не доказывает, что заголовок не имеет значения для всех поддерживаемых значений.

Составьте матрицу запросов до внесения изменений

Для синтетического руководства «Фигуры» предположим, что HTML предпочтителен при запросе HTML, обычный текст — при запросе обычного текста, а если Accept отсутствует, сервер возвращает HTML. Обе версии содержат одну и ту же нейтральную информацию: «круг, квадрат, треугольник». Это иллюстративные требования, а не результаты наблюдений за опубликованным сайтом.

Проверка Настройка запроса Ожидаемый результат Что проверить
HTML Accept: text/html Документ HTML Тело, Content-Type, Vary
Обычный текст Accept: text/plain Документ обычного текста Тело, Content-Type, Vary
По умолчанию Без поля Accept Документ HTML Выбор по умолчанию и Vary
Повтор HTML после обычного текста Снова документ HTML Влияет ли предыдущий вариант на доставку
Неиспользуемый вход Изменение заголовка, отсутствующего в правилах выбора То же выбранное представление Нужно ли исследовать этот заголовок

При первом сравнении оставьте сжатие без изменений. Иначе различие в байтах может быть связано со сжатием, а не с другим документом. Сначала исследуйте выбор формата, затем отдельно — сжатие. Это соответствует разным ролям Accept и Accept-Encoding. Согласование содержимого.

Фиксируйте значимые различия, а не только размер файла. В этом примере ответ с обычным текстом должен содержать названия фигур без HTML-разметки, а его тип медиа должен указывать на обычный текст. Если меняется генерируемая временная метка, это нужно исследовать, прежде чем считать каждое отличие в байтах новым вариантом.

Эта матрица помогает в диагностике, но не является полным набором тестов согласования содержимого. Когда базовые случаи заработают, добавьте реальные сочетания предпочтений и значений качества, которые поддерживает страница. Простой запрос с одним типом не проверяет все ветви алгоритма выбора.

Получите сопоставимые ответы в Терминале Mac

Вам понадобится общедоступный тестовый документ с синтетическим содержимым, его окончательный URL HTTPS и Mac с установленными bash и curl. В примере предполагается, что тестовый документ уже поддерживает описанное выше поведение с HTML и обычным текстом. Скрипт не создает, не загружает и не публикует этот документ.

Откройте Терминал и вставьте весь блок ниже. Когда появится запрос, введите URL синтетического документа. Скрипт создаст новую временную папку с отчетом и сохранит тело каждого ответа рядом с заголовками; ранее созданный отчет перезаписан не будет.

bash <<'BASH'
set -eu

printf 'Public synthetic page URL: ' > /dev/tty
IFS= read -r page_url < /dev/tty

case "$page_url" in
  https://*) ;;
  *) printf 'Enter an HTTPS URL.\n' >&2; exit 1 ;;
esac

report_dir=$(mktemp -d "${TMPDIR:-/tmp}/vary-check.XXXXXX")
printf 'Report directory: %s\n' "$report_dir"

for sample in html plain absent html-again; do
  case "$sample" in
    html|html-again) accept_header='Accept: text/html' ;;
    plain) accept_header='Accept: text/plain' ;;
    absent) accept_header='Accept:' ;;
  esac

  curl --disable --silent --show-error --fail \
    --connect-timeout 5 --max-time 20 \
    --header "$accept_header" \
    --header 'Accept-Encoding: identity' \
    --dump-header "$report_dir/$sample.headers" \
    --output "$report_dir/$sample.body" \
    --url "$page_url"
done

printf 'Finished. Responses saved in: %s\n' "$report_dir"
BASH

Здесь --header задает контролируемое поле запроса, а Accept: удаляет поле Accept, которое curl добавляет автоматически. Параметры --dump-header и --output сохраняют заголовки и тела отдельно. Ограничения времени соединения и передачи задают предел для каждого запроса. Эти параметры описаны в руководстве curl.

Скрипт останавливается, если curl сообщает об ошибке передачи или об HTTP-ошибке, на которую распространяется --fail. Перед повторной попыткой проверьте указанную папку: в ней могут остаться прежние снимки, а после неудачной передачи — неполные файлы. Скрипт намеренно не следует перенаправлениям, поэтому проверяйте строку статуса в каждом файле заголовков. Если вы получили перенаправление, используйте окончательный URL документа и запустите скрипт заново, чтобы создать новый отчет. Руководство curl.

Откройте папку с отчетом в Finder по пути, указанному скриптом. Просмотрите файлы в текстовом редакторе. Сравните html.body с plain.body, затем html.body с html-again.body. Так же внимательно изучите absent.headers, как и ответы на запросы с явно заданными предпочтениями.

Рассматривайте сохраненные результаты как наблюдения, сделанные в ходе этой последовательности запросов. Они не доказывают, что общий кэш что-либо сохранил. Чтобы проверить повторное использование кэша, повторите последовательность через предполагаемый путь доставки при документированных условиях кэширования, а затем поменяйте порядок и запросите сначала обычный текст.

Настройте слой, формирующий ответ

Для иллюстративного руководства «Фигуры» результаты выбора формата должны подтвердить, что Accept служит полем выбора. Настройте его там, где формируется или завершается HTTP-ответ. Если другой слой уже добавляет необходимый элемент Vary, сохраните его при добавлении элемента для выбора формата. Итоговый список должен описывать совокупное поведение выбора. RFC 9110: семантика HTTP.

Ниже приведен фрагмент заголовка ответа для примера, в котором используются выбор формата и согласование сжатия. Это не полный HTTP-ответ и не файл конфигурации сервера.

Vary: Accept, Accept-Encoding

Используйте один и тот же предполагаемый список Vary для согласованных вариантов и ответа по умолчанию, а также сохраняйте его в применимых ответах 304 Not Modified. MDN прямо указывает на это требование согласованности. Включите эти пути ответа в проверку, а не ограничивайтесь первым успешным ответом HTML. Заголовок Vary.

Добавление элемента meta с http-equiv="Vary" не является поддерживаемой заменой. WHATWG определяет конкретный набор директив-прагм HTML, в который Vary не входит, и поясняет, что эти директивы в основном отделены от заголовков HTTP. Настраивайте именно заголовок ответа. Стандарт HTML: директивы-прагмы.

Если ваш интерфейс публикации не позволяет задавать заголовки ответа, проверьте, поддерживает ли это уровень хостинга или приложения согласно документации. Если такой возможности нет, для этого синтетического примера можно использовать отдельные URL для HTML- и текстового документов со стабильными представлениями, вместо согласования их форматов по одному URL. Это устраняет именно этот параметр выбора; другие преобразования по-прежнему требуют отдельной оценки.

Диагностируйте отсутствующие, избыточные и вводящие в заблуждение вариации

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

Наблюдение Что исследовать дальше
Запросы HTML и обычного текста возвращают разные форматы, но в Vary нет Accept Проверьте место сборки окончательного заголовка ответа
В явных вариантах есть Accept, а в ответе по умолчанию его нет Проверьте путь ответа по умолчанию
Повторный запрос HTML возвращает версию обычного текста Сравните выбор на исходном сервере с доставкой через кэш
На все запросы возвращается один и тот же документ HTML Проверьте, существует ли согласование форматов, прежде чем добавлять связанный с форматом элемент
В Vary присутствует не относящийся к делу заголовок Прежде чем удалять его, найдите требующее его правило выбора
Изменение размера окна браузера меняет макет, но не доставленный HTML Проверьте, не является ли это адаптивным отображением, а не выбором на сервере

Случай с отсутствующим элементом в ответе по умолчанию требует особого внимания: RFC 9111 описывает, как отсутствие Vary в ответе по умолчанию может привести к выбору этого ответа для последующих запросов, даже если доступны альтернативы. Исправьте путь ответа по умолчанию вместе с явными вариантами. RFC 9111: кэширование HTTP.

Не используйте Vary: * как обходной путь для незавершенного перечня. Согласно правилам кэширования HTTP, сохраненный ответ с таким элементом всегда не проходит проверку на совпадение. Он не указывает, какие поля запроса выбирают ваш документ. RFC 9111: кэширование HTTP.

После сравнения в Терминале полезно также проверить поведение в браузере. В Fetch Standard WHATWG прямо учитывается Vary при выборе ответа из HTTP-кэша. Проверьте загрузку документа обычным способом через браузер, а также контролируемые запросы curl. Fetch Standard: получение по HTTP или из кэша.

Согласуйте доставку страницы с требованиями Google Search

Для страниц, отображение которых зависит от устройства, различайте адаптивный дизайн и динамическую подачу. Google описывает адаптивный дизайн как подачу одного и того же HTML по одному URL на разных устройствах, тогда как динамическая подача выбирает разный HTML по User-Agent и использует Vary: User-Agent. Google рекомендует адаптивный дизайн, поскольку его проще реализовать и поддерживать. Рекомендации по мобильным сайтам и индексации с приоритетом мобильных устройств.

Поэтому синтетическому руководству «Фигуры», которое только меняет расположение элементов в том же HTML с помощью CSS, не требуется User-Agent в Vary лишь из-за изменения макета. Если сервер действительно выбирает разный HTML для разных устройств, добавьте соответствующие случаи в матрицу запросов. Google также советует сохранять эквивалентность основного содержимого в версиях для компьютеров и мобильных устройств. Рекомендации по мобильным сайтам и индексации с приоритетом мобильных устройств.

В завершение составьте небольшой отчет о доставке, который удобно проверить: правила выбора документа, матрицу запросов, полученные ответы и итоговый список Vary. Для каждого указанного заголовка должна быть понятна его роль, все поддерживаемые варианты должны оставаться различимыми, а ответ по умолчанию должен соответствовать тому же контракту доставки.

Источники