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

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 %.
  • Избегайте необходимости вносить какие-либо изменения в контент со стороны авторов веб-сайта.
  • Минимизируйте сложность развертывания и избегайте изменений в сетевой инфраструктуре.
  • Разработайте этот новый протокол в сотрудничестве с сообществом открытого исходного кода.
  • Соберите реальные данные о производительности, чтобы (не) проверить экспериментальный протокол.

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

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

Перенесемся в 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 17 и черновой вариант 12 HPACK.
  • Август 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, и надеемся на его широкое распространение, учитывая широкое участие отрасли в стандартизации и внедрении. (Блог Chrome)

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

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

Более ранние версии протокола HTTP были специально разработаны для простоты реализации: HTTP/0.9 представлял собой однострочный протокол для загрузки Всемирной паутины; 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

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

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

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

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

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

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

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

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

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

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

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

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

Мультиплексирование запросов и ответов HTTP/2 внутри общего соединения

Снимок захватывает несколько потоков в процессе одного соединения. Клиент передает кадр 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

Зависимость потока в 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; 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 должен не только снизить задержку в сети, но также помочь повысить пропускную способность и снизить эксплуатационные расходы.

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

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

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

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

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

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

Нажатие на сервер

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

Сервер инициирует новые потоки (обещания) для push-ресурсов.

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

Фактически, если вы когда-либо встраивали 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. (См . Измерение и контроль накладных расходов протокола .) Чтобы уменьшить эти накладные расходы и повысить производительность, HTTP/2 сжимает метаданные заголовков запросов и ответов с использованием формата сжатия HPACK, в котором используются два простых, но мощных метода:

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

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

HPACK: сжатие заголовка для HTTP/2

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

Безопасность и производительность 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 .

дальнейшее чтение