web.dev LIVE is now over! Head to web.dev/live to watch all the sessions, see top Q&A, and more.

Введение в HTTP/2

Примечание. Следующее содержимое является выдержкой из Высокопроизводительная Браузерная Сеть (О'Рейли, Илья Григорик). Полную версию и связанный контент смотрите на hpbn.co.

HTTP/2 сделает наши приложения быстрее, проще и надежнее - редкая комбинация - благодаря тому, что мы можем отменить многие из обходных путей HTTP / 1.1, которые ранее делались в наших приложениях, и решить эти проблемы на транспортном уровне. Более того, он также открывает ряд совершенно новых возможностей для оптимизации наших приложений и повышения производительности!

Основными целями для HTTP/2 являются снижение задержки за счет обеспечения полного мультиплексирования запросов и ответов, минимизации накладных расходов протокола посредством эффективного сжатия полей заголовков HTTP и добавления поддержки приоритизации запросов и отправки на сервер. Для реализации этих требований существует большое число других улучшений протокола, таких как новые механизмы управления потоками, обработки ошибок и обновления, но это наиболее важные функции, которые каждый веб-разработчик должен понимать и использовать в своих приложениях.

HTTP/2 никак не изменяет семантику приложения HTTP. Все основные понятия, такие как методы HTTP, коды состояния, URI и поля заголовка, остаются на месте. Вместо этого HTTP/2 изменяет способ форматирования (кадрирования) данных и их транспортировки между клиентом и сервером, которые управляют всем процессом, и скрывает всю сложность наших приложений в новом слое кадрирования. В результате все существующие приложения могут быть доставлены без изменений.

Почему не HTTP/1.2?

Для достижения целей производительности, установленных рабочей группой HTTP, в HTTP/2 вводится новый уровень двоичного кадрирования, который обратно не совместим с предыдущими серверами и клиентами HTTP/1.x - отсюда и основной прирост версии протокола до HTTP/2.

Тем не менее, если вы не реализуете веб-сервер (или пользовательский клиент), работая с необработанными сокетами TCP, вы не увидите никакой разницы: все новое низкоуровневое кадрирование выполняется клиентом и сервером от вашего имени. Единственными заметными различиями будут улучшенная производительность и доступность новых возможностей, таких как расстановка приоритетов запросов, управление потоком и продвижение сервера.

Краткая история SPDY и HTTP/2

SPDY был экспериментальным протоколом, разработанным в Google и анонсированным в середине 2009 года, основной задачей которого было попытаться уменьшить задержку загрузки веб-страниц путем устранения некоторых известных ограничений производительности HTTP/1.1. В частности, намеченные цели проекта были установлены следующим образом:

  • Сокращение времени загрузки страницы (PLT) на 50%.
  • Отсутствие необходимости каких-либо изменений содержания со стороны авторов сайта.
  • Минимизация сложности развертывания и избежание изменений в сетевой инфраструктуре.
  • Разработка этого нового протокола в партнерстве с open-source сообществом.
  • Сбор реальных данных о производительности для проверки экспериментального протокола.

Примечание. Чтобы добиться улучшения PLT на 50%, SPDY стремился более эффективно использовать базовое TCP-соединение, вводя новый уровень двоичного кадрирования, чтобы обеспечить мультиплексирование запросов и ответов, расстановку приоритетов и сжатие заголовков; см. Задержка, как узкое место в производительности.

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

До сих пор мы тестировали SPDY только в лабораторных условиях. Первоначальные результаты очень обнадеживают: когда мы загружаем 25 лучших веб-сайтов по симулированным соединениям домашней сети, мы видим значительное улучшение производительности - страницы загружаются на 55% быстрее. (Chromium Blog)

Перенесемся в 2012 год, и новый экспериментальный протокол был поддержан в Chrome, Firefox и Opera, и быстро растущее число сайтов, как крупных (например, Google, Twitter, Facebook), так и небольших, развертывали SPDY в своей инфраструктуре. По сути, SPDY стала стандартом де-факто благодаря растущему внедрению в отрасли.

Наблюдая за этой тенденцией, Рабочая группа HTTP (HTTP-WG) извлекла уроки из SPDY, собрала и улучшила его, а также предоставила официальный стандарт «HTTP/2». Был составлен новый устав, был проведен открытый конкурс предложений HTTP/2, и после большого обсуждения в рабочей группе спецификация SPDY была принята в качестве отправной точки для нового протокола HTTP/2.

В течение следующих нескольких лет SPDY и HTTP/2 продолжали параллельно развиваться, причем SPDY выступал в качестве экспериментальной ветви, которая использовалась для тестирования новых функций и предложений по стандарту HTTP/2. То, что хорошо выглядит на бумаге, может не сработать на практике, и наоборот, и SPDY предложила маршрут для тестирования и оценки каждого предложения до его включения в стандарт HTTP/2. В итоге этот процесс занял три года и привел к созданию более десятка промежуточных проектов:

  • Март 2012: запрос предложений для HTTP/2
  • Ноябрь 2012: первый проект HTTP/2 (на основе SPDY)
  • Август 2014: опубликованы черновик HTTP/2 и черновик HPACK-12
  • Август 2014 года: последний звонок Рабочей группы по HTTP/2
  • Февраль 2015: IESG утвердил черновики HTTP/2 и HPACK
  • Май 2015: опубликованы RFC 7540 (HTTP/2) и RFC 7541 (HPACK)

В начале 2015 года IESG рассмотрела и одобрила новый стандарт HTTP/2 для публикации. Вскоре после этого команда Google Chrome объявила о своем намерении отказаться от расширений SPDY и NPN для TLS:

Основные изменения HTTP/2 по сравнению с HTTP/1.1 направлены на повышение производительности. Некоторые ключевые функции, такие как мультиплексирование, сжатие заголовков, расстановка приоритетов и согласование протоколов, возникли в результате работы, выполненной в ранее открытом, но нестандартном протоколе с именем SPDY. Chrome поддерживает SPDY начиная с Chrome 6, но, поскольку большинство преимуществ присутствует в HTTP/2, пришло время попрощаться. Мы планируем отменить поддержку SPDY в начале 2016 года, а также одновременно отменить поддержку расширения TLS с именем NPN в пользу ALPN в Chrome. Разработчикам серверов настоятельно рекомендуется перейти на HTTP/2 и ALPN.

Мы рады, что внесли свой вклад в процесс открытых стандартов, который привел к созданию HTTP/2, и надеемся увидеть широкое распространение, учитывая широкое участие отрасли в стандартизации и реализации. (Chromium Blog)

Совместная разработка SPDY и HTTP/2 позволила разработчикам серверов, браузеров и сайтов получить реальный опыт работы с новым протоколом в процессе его разработки. В результате стандарт HTTP/2 является одним из лучших и наиболее тщательно протестированных стандартов. К тому времени, когда IESG утвердил HTTP/2, было множество проверенных и готовых к внедрению клиентских и серверных реализаций. Фактически, всего через несколько недель после утверждения окончательного протокола многие пользователи уже воспользовались его преимуществами, поскольку несколько популярных браузеров (и многие сайты) развернули полную поддержку HTTP/2.

Дизайн и технические цели

Ранние версии протокола HTTP были специально разработаны для простоты реализации: HTTP/0.9 был однострочным протоколом для начальной загрузки World Wide Web; HTTP/1.0 документировал популярные расширения HTTP/0.9 в информационном стандарте; HTTP/1.1 ввел официальный стандарт IETF; смотрите краткую историю HTTP. Таким образом, HTTP/0.9-1.x предоставил именно то, что намеревался сделать: HTTP является одним из наиболее распространенных прикладных протоколов в Интернете.

К сожалению, простота реализации также привела к снижению производительности приложений: клиентам HTTP/1.x необходимо использовать несколько соединений для достижения параллелизма и уменьшения задержки; HTTP/1.x не сжимает заголовки запроса и ответа, вызывая ненужный сетевой трафик; HTTP/1.x не позволяет эффективно расставлять приоритеты ресурсов, что приводит к плохому использованию основного TCP-соединения; и так далее.

Эти ограничения не были фатальными, но поскольку веб-приложения продолжали расти в своих масштабах, сложности и важности в нашей повседневной жизни, они налагали растущее бремя как на разработчиков, так и на пользователей Интернета, что является именно тем разрывом, разрешить который и был разработан HTTP/2:

HTTP/2 позволяет более эффективно использовать сетевые ресурсы и уменьшить восприятие задержки, внедряя сжатие полей заголовка и позволяя несколько одновременных обменов по одному и тому же соединению… В частности, это позволяет чередовать сообщения запроса и ответа по одному и тому же соединению и использует эффективное кодирование полей заголовка HTTP. Это также позволяет назначать приоритеты запросам, позволяя более важным запросам выполняться быстрее, что еще больше повышает производительность. Полученный протокол более дружественен для сети, поскольку можно использовать меньше TCP-соединений по сравнению с HTTP/1.x. Это означает меньшую конкуренцию с другими потоками и более долговечные соединения, что, в свою очередь, приводит к лучшему использованию доступной емкости сети. Наконец, HTTP/2 также обеспечивает более эффективную обработку сообщений за счет использования двоичного фрейма сообщения. (Протокол передачи гипертекста, версия 2, проект 17)

Важно отметить, что HTTP/2 расширяет, а не заменяет предыдущие стандарты HTTP. Семантика приложения HTTP одинакова, и не было внесено никаких изменений в предлагаемую функциональность или основные понятия, такие как методы HTTP, коды состояния, URI и поля заголовка. Эти изменения явно вышли за рамки возможностей HTTP/2. Тем не менее, хотя высокоуровневый API остается неизменным, важно понимать, как низкоуровневые изменения устраняют ограничения производительности предыдущих протоколов. Давайте кратко рассмотрим бинарный слой кадрирования и его особенности.

Двоичный кадровый слой

В основе всех улучшений производительности HTTP/2 лежит новый уровень двоичного кадрирования, который определяет, как HTTP-сообщения инкапсулируются и передаются между клиентом и сервером.

HTTP/2 binary framing layer

«Слой» относится к выбору проекта для введения нового оптимизированного механизма кодирования между интерфейсом сокета и более высоким HTTP API, предоставляемым нашим приложениям: семантика HTTP, такая как глаголы, методы и заголовки, не затрагивается, но способ, которым они закодированы в то время как в пути отличается. В отличие от открытого текста HTTP/1.x протокола с разделителями новой строки, вся связь HTTP/2 разделена на меньшие сообщения и кадры, каждое из которых кодируется в двоичном формате.

В результате и клиент, и сервер должны использовать новый механизм двоичного кодирования, чтобы понимать друг друга: клиент HTTP/1.x не будет понимать сервер только HTTP/2, и наоборот. К счастью, наши приложения блаженно не знают обо всех этих изменениях, так как клиент и сервер выполняют всю необходимую работу по созданию кадров от нашего имени.

Потоки, сообщения и кадры

Введение нового бинарного механизма кадрирования меняет способ обмена данными между клиентом и сервером. Чтобы описать этот процесс, давайте ознакомимся с терминологией HTTP/2:

  • Поток : двунаправленный поток байтов в установленном соединении, который может нести одно или несколько сообщений.
  • Сообщение : полная последовательность кадров, которые отображаются на логический запрос или ответное сообщение.
  • Кадр : наименьшая единица связи в HTTP/2, каждая из которых содержит заголовок кадра, который как минимум идентифицирует поток, которому принадлежит кадр.

Соотношение этих терминов можно обобщить следующим образом:

  • Вся связь осуществляется через одно TCP-соединение, которое может переносить любое количество двунаправленных потоков.
  • Каждый поток имеет уникальный идентификатор и необязательную информацию о приоритете, которая используется для передачи двунаправленных сообщений.
  • Каждое сообщение является логическим HTTP-сообщением, таким как запрос или ответ, который состоит из одного или нескольких кадров.
  • Кадр - это наименьшая единица связи, которая переносит данные определенного типа - например, заголовки HTTP, полезную нагрузку сообщения и т. Д. Кадры из разных потоков могут чередоваться и затем повторно собираться через встроенный идентификатор потока в заголовке каждого кадра.

HTTP/2 streams, messages, and frames

Короче говоря, HTTP/2 разбивает связь по протоколу HTTP на обмен двоично-закодированными кадрами, которые затем сопоставляются с сообщениями, которые принадлежат конкретному потоку, и все они мультиплексируются в одном TCP-соединении. Это основа, которая обеспечивает все другие функции и оптимизации производительности, предоставляемые протоколом HTTP/2.

Мультиплексирование запросов и ответов

В HTTP/1.x, если клиент хочет сделать несколько параллельных запросов для повышения производительности, необходимо использовать несколько соединений TCP (см. Использование нескольких соединений TCP ). Такое поведение является прямым следствием модели доставки HTTP/1.x, которая гарантирует, что за один раз может быть доставлен только один ответ (очередь ответов) для каждого соединения. Хуже того, это также приводит к блокировке заголовка строки и неэффективному использованию основного TCP-соединения.

Новый уровень двоичного кадрирования в HTTP/2 устраняет эти ограничения и обеспечивает полное мультиплексирование запросов и ответов, позволяя клиенту и серверу разбивать HTTP-сообщение на независимые кадры, чередовать их, а затем повторно собирать их на другом конце.

HTTP/2 request and response multiplexing within a shared connection

Снимок захватывает несколько потоков в полете в пределах одного соединения. Клиент передает кадр DATA (поток 5) на сервер, в то время как сервер передает клиенту чередующуюся последовательность кадров для потоков 1 и 3. В результате в полете три параллельных потока.

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

  • Чередовать несколько запросов параллельно, не блокируя ни один.
  • Чередовать несколько ответов параллельно, не блокируя ни один.
  • Использовать одно соединение для одновременной доставки нескольких запросов и ответов.
  • Удалить ненужные обходные пути HTTP/1.x (см. Оптимизация для HTTP/1.x, например, связанные файлы, спрайты изображений и шардинг домена).
  • Снизить время загрузки страницы, устраняя ненужные задержки и улучшая использование доступной емкости сети.
  • И многое другое…

Новый уровень двоичного кадрирования в HTTP/2 решает проблему блокировки заголовка строки, обнаруженную в HTTP/1.x, и устраняет необходимость в нескольких соединениях для обеспечения параллельной обработки и доставки запросов и ответов. В результате это делает наши приложения быстрее, проще и дешевле в развертывании.

Приоритетность потоков

Как только HTTP-сообщение может быть разделено на множество отдельных кадров, и мы допускаем мультиплексирование кадров из нескольких потоков, порядок, в котором кадры чередуются и доставляются как клиентом, так и сервером, становится критическим фактором производительности. Чтобы облегчить это, стандарт HTTP/2 позволяет каждому потоку иметь связанный вес и зависимость:

  • Каждому потоку может быть присвоен целочисленный вес от 1 до 256.
  • Каждому потоку может быть дана явная зависимость от другого потока.

Комбинация потоковых зависимостей и весов позволяет клиенту построить и передать «дерево приоритетов», которое выражает то, как он предпочел бы получать ответы. В свою очередь, сервер может использовать эту информацию для определения приоритетов потоковой обработки, управляя выделением ЦП, памяти и других ресурсов, и, как только будут получены данные ответов, выделением полосы пропускания, чтобы обеспечить оптимальную доставку высокоприоритетных ответов клиенту.

HTTP/2 stream dependencies and weights

Зависимость потока в HTTP/2 объявляется путем ссылки на уникальный идентификатор другого потока в качестве его родителя; если идентификатор опущен, говорят, что поток зависит от «корневого потока». Объявление потоковой зависимости означает, что, если это возможно, родительскому потоку должны быть выделены ресурсы перед его зависимостями. Другими словами: «Пожалуйста, обработайте и доставьте ответ D до ответа C».

Потоки, которые совместно используют один и тот же родительский элемент (другими словами, потоки одного уровня), должны распределять ресурсы пропорционально их весу. Например, если вес потока A равен 12, а вес одного его брата B равен 4, то для определения доли ресурсов, которые должен получить каждый из этих потоков:

  1. Суммируйте все веса: 4 + 12 = 16
  2. Разделите вес каждого потока на общий вес: A = 12/16, B = 4/16

Таким образом, поток A должен получать три четверти, а поток B - четверть доступных ресурсов; Поток B должен получить треть ресурсов, выделенных для потока A. Давайте рассмотрим еще несколько практических примеров на рисунке выше. Слева направо:

  1. Ни поток A, ни B не определяют родительскую зависимость и, как говорят, зависят от неявного «корневого потока»; Вес A равен 12, а вес B равен 4. Таким образом, на основе пропорциональных весов: поток B должен получать треть ресурсов, выделенных для потока A.
  2. Поток D зависит от корневого потока; C зависит от D. Таким образом, D должен получить полное распределение ресурсов раньше C. Веса несущественны, потому что зависимость C передает более сильное предпочтение.
  3. Поток D должен получить полное распределение ресурсов перед C; C должен получить полное распределение ресурсов перед A и B; поток B должен получать треть ресурсов, выделенных потоку A.
  4. Поток D должен получить полное распределение ресурсов перед E и C; E и C должны получить равное распределение перед A и B; А и В должны получать пропорциональное распределение в зависимости от их веса.

Как показывают вышеприведенные примеры, комбинация потоковых зависимостей и весов обеспечивает выразительный язык для определения приоритетов ресурсов, что является критической функцией для повышения производительности просмотра, когда у нас есть много типов ресурсов с различными зависимостями и весами. Более того, протокол HTTP/2 также позволяет клиенту обновлять эти настройки в любой момент, что обеспечивает дальнейшую оптимизацию в браузере. Другими словами, мы можем изменять зависимости и перераспределять веса в ответ на взаимодействие с пользователем и другие сигналы.

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

Одно соединение на источник

Благодаря новому механизму двоичного кадрирования HTTP/2 больше не требует нескольких TCP-соединений для параллельного мультиплексирования потоков; каждый поток разбивается на множество кадров, которые могут чередоваться и расставляться по приоритетам. В результате все соединения HTTP/2 являются постоянными, и для каждого источника требуется только одно соединение, что дает многочисленные преимущества в производительности.

Как для SPDY, так и для HTTP/2, функцией-убийцей является произвольное мультиплексирование в одном канале, контролируемом заторами. Меня поражает, насколько это важно и насколько хорошо это работает. Одна большая метрика вокруг того, что мне нравится, это доля созданных соединений, которые переносят только одну HTTP-транзакцию (и, следовательно, делают эту транзакцию несущей все накладные расходы). Для HTTP/1 74% наших активных соединений несут только одну транзакцию - постоянные соединения не так полезны, как все мы хотим. Но в HTTP/2 это число падает до 25%. Это огромная победа для сокращения накладных расходов. (HTTP/2 - Жить в Firefox, Патрик МакМанус)

Большинство передач HTTP короткие и импульсные, тогда как TCP оптимизирован для длительных объемных передач данных. Повторно используя одно и то же соединение, HTTP/2 может более эффективно использовать каждое TCP-соединение, а также значительно снизить общие издержки протокола. Кроме того, использование меньшего количества соединений уменьшает объем памяти и объем обработки по всему пути соединения (другими словами, клиент, посредники и серверы происхождения). Это снижает общие эксплуатационные расходы и улучшает использование сети и пропускную способность. В результате переход на HTTP/2 должен не только уменьшить задержку в сети, но и помочь повысить пропускную способность и снизить эксплуатационные расходы.

Примечание. Сокращение числа подключений является особенно важной функцией для повышения производительности развертываний HTTPS: это приводит к сокращению затратных рукопожатий TLS, лучшему повторному использованию сеансов и общему сокращению требуемых ресурсов клиента и сервера.

Управление потоком

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

Напоминают ли вышеупомянутые требования об управлении потоком TCP? Они должны, так как проблема фактически идентична (см. Контроль потока ). Однако поскольку потоки HTTP/2 мультиплексируются в одном TCP-соединении, управление потоками TCP не является достаточно детализированным и не обеспечивает API-интерфейсы уровня приложения, необходимые для регулирования доставки отдельных потоков. Для решения этой проблемы HTTP/2 предоставляет набор простых строительных блоков, которые позволяют клиенту и серверу реализовывать свои собственные средства управления потоками на уровне потоков и соединений:

  • Управление потоком является направленным. Каждый получатель может выбрать любой размер окна, который он желает для каждого потока и всего соединения.
  • Контроль потока основан на кредите. Каждый получатель объявляет свое начальное соединение и окно управления потоком потока (в байтах), которое уменьшается всякий раз, когда отправитель испускает кадр DATA и увеличивается с помощью кадра WINDOW_UPDATE отправленного получателем.
  • Управление потоком невозможно отключить. Когда установлено соединение HTTP/2, клиент и сервер обмениваются кадрами SETTINGS, которые устанавливают размеры окна управления потоком в обоих направлениях. Значение по умолчанию окна управления потоком установлено в 65 535 байт, но получатель может установить большой максимальный размер окна ( 2^31-1 байт) и поддерживать его, отправляя кадр WINDOW_UPDATE при получении любых данных.
  • Управление потоком - переход за переходом, а не сквозной. То есть посредник может использовать его для управления использованием ресурсов и реализации механизмов распределения ресурсов на основе собственных критериев и эвристики.

HTTP/2 не определяет какой-либо конкретный алгоритм для реализации управления потоком. Вместо этого он предоставляет простые строительные блоки и переносит реализацию на клиент и сервер, которые могут использовать его для реализации пользовательских стратегий для регулирования использования и распределения ресурсов, а также для реализации новых возможностей доставки, которые могут помочь улучшить как реальную, так и воспринимаемую производительность. (см. Скорость, производительность и восприятие человеком ) наших веб-приложений.

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

Push-сервер

Еще одна мощная новая функция HTTP/2 - возможность сервера отправлять несколько ответов на один клиентский запрос. То есть, в дополнение к ответу на исходный запрос, сервер может отправить клиенту дополнительные ресурсы (рис. 12-5), при этом клиенту не нужно явно запрашивать каждый из них.

Server initiates new streams (promises) for push resources

Примечание: HTTP/2 отрывается от строгой семантики запроса-ответа и обеспечивает рабочие процессы push-to-one-on-server, инициируемые сервером, которые открывают мир новых возможностей взаимодействия как внутри, так и вне браузера. Это полезная функция, которая будет иметь важные долгосрочные последствия как для того, как мы думаем о протоколе, так и где и как он используется.

Зачем нам нужен такой механизм в браузере? Типичное веб-приложение состоит из десятков ресурсов, все из которых обнаруживаются клиентом путем изучения документа, предоставленного сервером. В результате, почему бы не устранить лишнюю задержку и позволить серверу заблаговременно выдвигать связанные ресурсы? Сервер уже знает, какие ресурсы потребуются клиенту; это толчок сервера.

На самом деле, если вы когда-либо вставляли CSS, JavaScript или любой другой ресурс через URI данных (см. Раздел «Внедрение ресурсов» ), то у вас уже есть практический опыт работы с сервером. Внедряя ресурс в документ вручную, мы, по сути, передаем этот ресурс клиенту, не дожидаясь, пока клиент запросит его. С HTTP/2 мы можем достичь тех же результатов, но с дополнительными преимуществами производительности. Push-ресурсы могут быть:

  • Кэшируемые клиентом
  • Повторно используемые на разных страницах
  • Мультиплексированы вместе с другими ресурсами
  • Приоритезированы сервером
  • Отклонены клиентом

PUSH_PROMISE 101

Все push-потоки сервера инициируются через кадры PUSH_PROMISE, которые сигнализируют о намерении сервера передать описанные ресурсы клиенту и должны быть доставлены раньше данных ответа, которые запрашивают отправленные ресурсы. Этот порядок доставки имеет решающее значение: клиент должен знать, какие ресурсы сервер намерен использовать, чтобы избежать дублирования запросов для этих ресурсов. Самая простая стратегия для удовлетворения этого требования - отправить все кадры PUSH_PROMISE , которые содержат только заголовки HTTP обещанного ресурса, перед ответом родителя (другими словами, кадрами DATA ).

Как только клиент получает кадр PUSH_PROMISE у него есть возможность отклонить поток (через кадр RST_STREAM ), если он этого хочет. (Это может произойти, например, потому что ресурс уже находится в кеше.) Это важное улучшение по сравнению с HTTP/1.x. Напротив, использование встраивания ресурсов, которое является популярной «оптимизацией» для HTTP/1.x, эквивалентно «принудительному выталкиванию»: клиент не может отказаться, отменить его или обработать встроенный ресурс индивидуально.

С HTTP/2 у клиента остается полный контроль над тем, как используется push-запрос сервера. Клиент может ограничить количество одновременно передаваемых потоков; настроить начальное окно управления потоком, чтобы контролировать объем данных, передаваемых при первом открытии потока; или полностью отключить принудительное использование сервера. Эти предпочтения передаются через кадры SETTINGS в начале соединения HTTP/2 и могут быть обновлены в любое время.

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

Сжатие заголовка

Каждая HTTP передача содержит набор заголовков, которые описывают переданный ресурс и его свойства. В HTTP/1.x эти метаданные всегда отправляются в виде простого текста и добавляют от 500 до 800 байтов служебных данных на передачу, а иногда и больше килобайт, если используются файлы cookie HTTP. (См. Измерение и управление издержками {a1}протокола{/a1} .) Чтобы уменьшить эти издержки и повысить производительность, HTTP/2 сжимает метаданные заголовка запроса и ответа, используя формат сжатия HPACK, который использует два простых, но мощных метода:

  1. Позволяет кодировать передаваемые поля заголовка через статический код Хаффмана, что уменьшает их индивидуальный размер передачи.
  2. Требует, чтобы и клиент, и сервер поддерживали и обновляли индексированный список ранее просматриваемых полей заголовка (другими словами, он устанавливает общий контекст сжатия), который затем используется в качестве ссылки для эффективного кодирования ранее переданных значений.

Кодирование Хаффмана позволяет сжимать отдельные значения при передаче, а индексированный список ранее переданных значений позволяет нам кодировать повторяющиеся значения путем передачи значений индекса, которые можно использовать для эффективного поиска и восстановления ключей и значений полного заголовка.

HPACK: Header Compression for HTTP/2

В качестве еще одной оптимизации контекст сжатия HPACK состоит из статической и динамической таблицы: статическая таблица определена в спецификации и предоставляет список общих полей заголовка HTTP, которые могут использовать все соединения (например, допустимые имена заголовков); динамическая таблица изначально пуста и обновляется на основе обмениваемых значений в конкретном соединении. В результате размер каждого запроса уменьшается за счет использования статического кодирования Хаффмана для значений, которые не были видны ранее, и замещения индексов для значений, которые уже присутствуют в статических или динамических таблицах на каждой стороне.

Примечание. Определения полей заголовка запроса и ответа в HTTP/2 остаются неизменными, за исключением нескольких незначительных исключений: все имена полей заголовка строчные, а строка запроса теперь разделена на отдельные поля псевдо-заголовка :method :scheme :authority и :path.

Безопасность и производительность HPACK

Ранние версии HTTP/2 и SPDY использовали zlib со специальным словарем для сжатия всех заголовков HTTP. Это позволило сократить размер передаваемых данных заголовка на 85-88% и значительно сократить время загрузки страницы:

На канале DSL с низкой пропускной способностью, в котором ссылка на загрузку составляет всего 375 Кбит/с, сжатие заголовка запроса, в частности, привело к значительному увеличению времени загрузки страницы для определенных сайтов (иными словами, для тех, которые отправляли большое количество запросов ресурсов). Мы обнаружили сокращение времени загрузки страницы на 45–1142 мс просто из-за сжатия заголовка. (Техническая статья SPDY, chromium.org)

Однако летом 2012 года была опубликована атака безопасности CRIME на алгоритмы сжатия TLS и SPDY, что могло привести к перехвату сеанса. В результате алгоритм сжатия zlib был заменен HPACK, который был специально разработан для: устранения обнаруженных проблем безопасности, эффективности и простоты для правильной реализации и, конечно же, обеспечения хорошего сжатия метаданных заголовка HTTP.

Для получения полной информации об алгоритме сжатия HPACK см. IETF HPACK - Сжатие заголовка для HTTP / 2 .

Дальнейшее чтение:

Обратная связь

Was this page helpful?
Yes
What was the best thing about this page?
It helped me complete my goal(s)
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had the information I needed
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had accurate information
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was easy to read
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
Something else
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
No
What was the worst thing about this page?
It didn't help me complete my goal(s)
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was missing information I needed
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It had inaccurate information
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
It was hard to read
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.
Something else
Thank you for the feedback. If you have specific ideas on how to improve this page, please create an issue.