Сжатие ресурсов
Передача текстового файла может занимать заметную часть пути, особенно в условиях ограниченного канала. Один способ уменьшить эту часть — доставить те же данные в сжатом представлении. Однако наличие файла с расширением .gz в проекте ещё не объясняет, что получил браузер. В этом уроке научимся проверять договор ответа и сравнивать размеры без подмены содержимого.
Продолжаем модель мобильной сети. Результат — протокол ручной проверки одного ресурса: согласованная кодировка, сохранённые байты, восстановленное содержимое и ограничения вывода. Автор не запускал команды и не измерял ProfessorWeb. Стандартный статический сервер из архива не настроен на HTTP-компрессию; для этого упражнения читатель отдельно готовит собственный локальный сервер.
Формат документа и его представление
HTML остаётся HTML после распаковки, а JavaScript — исходным текстом программы. Content-Type описывает тип содержимого, Content-Encoding — применённую к представлению кодировку. Браузер снимает эту кодировку прежде, чем использовать содержимое по назначению. Назначение заголовка и порядок кодировок описаны в MDN: Content-Encoding.
Сжатие без потерь не является удалением абзацев или уменьшением количества функций. Можно сократить передаваемые байты, сохранив большой объём JavaScript для разбора и исполнения. Поэтому сетевой выигрыш не отменяет стоимость программы. После готовности ресурса исходные действия остаются и должны рассматриваться отдельно.
Не смешивайте эту операцию с минификацией. Минификация меняет исходный текст по правилам инструмента, а компрессия кодирует уже выбранные байты для доставки. В контролируемом сравнении сначала сохраняйте один исходный файл. Если одновременно удалить комментарии, переписать программу и включить компрессию, причины различий окажутся объединены.
Запрос не гарантирует сжатый ответ
Клиент сообщает поддерживаемые кодировки через Accept-Encoding, сервер выбирает фактическое представление и обозначает его в ответе. Он может вернуть несжатые данные, когда такое представление допустимо: например, из-за правил размера, типа содержимого или доступных ресурсов. Запрос с gzip не доказывает, что ответ действительно имеет Content-Encoding: gzip. Это согласование описано в MDN: Accept-Encoding.
Пусть читатель подготовил отдельный локальный ресурс article.html на порту 4197. Это условный адрес упражнения, не работающий сервис, который был создан автором. Сначала убедитесь, что он возвращает нужный документ, а не страницу ошибки. Затем сравните два GET-запроса к одному URL с разными разрешёнными представлениями.
curl -sS -D headers-identity.txt -H 'Accept-Encoding: identity' -o body-identity.bin http://127.0.0.1:4197/article.html
curl -sS -D headers-gzip.txt -H 'Accept-Encoding: gzip' -o body-gzip.bin http://127.0.0.1:4197/article.html
Это инструкция для самостоятельного выполнения. Имена файлов обозначают намерение запроса, но окончательный вывод делается по заголовкам. В обоих ответах проверьте успешный статус, ожидаемый тип документа и фактическую кодировку. Если второй ответ тоже несжатый, сохраните этот результат: настройка ещё не дала исследуемого представления, и сравнение компрессии начинать рано.
Не ограничивайтесь HEAD. Для проверки размеров и восстановленного текста требуется тело выбранного GET-ответа. Редирект, ошибка или разная версия исходного документа нарушают условия опыта. Запишите также отсутствие изменений файла между запросами, иначе разницу байтов можно ошибочно объяснить алгоритмом сжатия.
Почему здесь нет автоматической распаковки
В командах намеренно отсутствует --compressed. Эта опция curl запрашивает поддерживаемое сжатие и автоматически декодирует полученное содержимое. Сохранённый файл тогда может уже содержать распакованный текст, хотя отдельно записанные заголовки по-прежнему называют кодировку. Такое поведение описано в официальном руководстве curl.
Наша цель другая: сохранить кодированное тело, затем отдельно проверить его. Опция --raw тоже не нужна: она отключает обработку не только кодировки содержимого, но и кодировки передачи. Тогда служебное обрамление передачи способно попасть в файл и изменить смысл сравниваемого размера. Мы исследуем тело представления, а не полный набор байтов сетевого протокола.
Если сохранённые заголовки подтвердили gzip, читатель может выполнить отдельную распаковку и сравнение:
wc -c body-identity.bin body-gzip.bin
gzip -dc body-gzip.bin > body-restored.bin
cmp body-identity.bin body-restored.bin
Ожидаемый функциональный результат для одинакового исходного документа — совпадение восстановленных байтов. Если сравнение сообщает различие, сначала разберите версии, ответ сервера и правильность декодирования. Уменьшенный файл с другим содержимым не является доказательством корректной компрессии. Не распаковывайте как gzip ответ, чьи заголовки называют другую кодировку или не называют её вовсе.
Три размера в браузере
В Resource Timing есть размеры кодированного и декодированного тела. encodedBodySize относится к телу до снятия кодировок содержимого, decodedBodySize — после. Их определения приведены в MDN: encodedBodySize и decodedBodySize. Это полезное дополнение к заголовкам конкретного ответа.
const rows = performance.getEntriesByType("resource").map(entry => ({
url: entry.name,
encodedBody: entry.encodedBodySize,
decodedBody: entry.decodedBodySize,
transferred: entry.transferSize
}));
console.table(rows);
Фрагмент предназначен для локального исследования собственных ресурсов; он ничего не отправляет. transferSize учитывает переданное тело вместе с заголовками и может равняться нулю при локальном попадании в кеш. Междоменный ресурс без разрешения Timing-Allow-Origin тоже ограничивает доступные сведения. Эти условия указаны в MDN: transferSize. Нулевое значение нельзя автоматически считать нулевым размером документа.
Записывайте происхождение каждого числа. Размер файла на диске, размер тела ответа и объём передачи отвечают на разные вопросы. Для текущего документа запись относится к типу navigation, а приведённый фрагмент выбирает подресурсы типа resource. Отсутствие HTML в этой таблице не означает, что браузер его не получал.
Для учебной арифметики представим тело в 100 КиБ, которое после сжатия занимает 30 КиБ. Оба числа придуманы и не относятся к исходникам архива. Доля сокращения равна 70 процентам размера тела. Из этого не следует сокращение времени страницы на 70 процентов: остаются ожидание ответа, другие ресурсы и обработка. В отчёте называйте объект процента, иначе точная формула создаст неточное обещание.
Даже декодированный размер не является размером занятой памяти. Браузер создаёт внутренние структуры документа и программы, изображения распаковываются для отображения. Поэтому три столбца таблицы нельзя использовать как готовую оценку памяти вкладки. Они описывают доставку тела и помогают выбрать следующую проверку, сохраняя предел своего назначения.
Разные представления одного URL
Если выбор представления зависит от Accept-Encoding, кешу нужен соответствующий договор. Vary: Accept-Encoding сообщает, что заголовок участвовал в выборе ответа. Согласованность этого значения нужна и для несжатого варианта, и для последующей проверки свежести. Механизм описан в MDN: Vary.
Здесь мы исследуем представление, а настройку хостинга и сроков хранения оставляем материалам о развёртывании и HTTP-кеше. Сжатие не исправляет выдачу устаревшей версии файла. При диагностике сначала убедитесь, что обе стороны сравнения получили нужную версию содержимого, затем обсуждайте её кодировку.
Текст обычно предлагает повторяющиеся последовательности, однако уже сжатое изображение может плохо поддаваться повторному сжатию. Нет правила, что каждый ресурс обязательно станет меньше. Кроме размера учитывайте подготовку представления на сервере, распаковку и последующую обработку. Предварительное сжатие статических файлов и сжатие при ответе имеют разные эксплуатационные расходы; решение требует отдельной конфигурации.
Завершите протокол реальными наблюдениями читателя либо оставьте поля пустыми. Укажите URL, версию, запрос, заголовки, оба размера и совпадение восстановленного текста. Только после этого сопоставляйте временную цепочку при одинаковой сети и кеше. Даже корректное уменьшение тела ещё не доказывает улучшение LCP, если ограничение находилось в другой фазе.
Скачать исходники продолжения. Следующий урок: разбор регрессии скорости.