Чи HTTP / 2 робить веб-розетки застарілими?


268

Я дізнаюся про протокол HTTP / 2. Це двійковий протокол з невеликими кадрами повідомлень. Це дозволяє потік мультиплексування через один TCP-з'єднання. Концептуально це схоже на WebSockets.

Чи планується застаріти веб-розетки та замінити їх якимись безголовними запитами HTTP / 2 та ініційованими сервером push-повідомленнями? Або WebSockets доповнить HTTP / 2?


Я вважаю, що прийнята відповідь є правильною, веб-розетки все ще є бажаним рішенням для веб-додатків для спілкування з сервером двосторонньо, включаючи повідомлення, натиснуті на сервер. HTTP використовується для більш ніж просто браузерів, і коли і клієнт, і сервер можуть використовувати API низького рівня, їм не потрібні веб-розетки. Досі більшість людей використовує HTTP для веб-додатків і в основному стурбовані JavaScript-експозиціями. Якщо модератори вважають, що прийнята відповідь має бути різною, я не проти цього, оскільки це питання, мабуть, породжує багато поглядів, і моя думка може бути помилковою.
вбеженар

Відповіді:


161

З того, що я зрозумів, HTTP / 2 не є заміною websocket, а має на меті стандартизувати протокол SPDY.

У HTTP / 2 сервер-натиск використовується поза кадром для поліпшення завантаження ресурсів клієнтом із браузера. Як розробник, ви не дуже дбаєте про це під час свого розвитку. Однак, за допомогою Websocket, розробник може використовувати API, який здатний споживати та надсилати повідомлення за допомогою унікального повнодуплексного з'єднання.

Це не однакові речі, і вони повинні доповнювати одна одну.


3
Дякую Гійом за вашу відповідь. Однак мені цікаво, чи могли ви (або хтось) додати якусь посилання з специфікації HTTP / 2. Що я читав з блогів і так далі - з HTTP / 2 існує справжня двостороння комунікація?
Мартін Мізер

3
Не впевнений, що специфікація HTTP / 2 є правильним місцем для детальної інформації про походження HTTP / 2 та про те, чим він відрізняється від websocket. Однак ви легко бачите, що з HTTP / 2 ми використовуємо двосторонній зв’язок: goo.gl/IJVxWS (стор. 6 та 13)
Гійом D.

27
HTTP / 2 дійсно двосторонній, але не симетричний, це означає, що тільки клієнт може надіслати належний запит, а сервер може надсилати відповіді та запитувати обіцянки (натискання). Це робить веб-розетки різними в тому сенсі, що обидві сторони більш "рівні" з точки зору того, що їм дозволено надсилати / отримувати.
Георгій Антоніадіс

3
У програмі IEEE Software Engineering Radio є чудовий подкаст про походження HTTP2. Я думаю, це все: se-radio.net/2015/07/episode-232-mark-nottingham-on-http2
Макс Мерфі

2
подібну відповідь з повним обґрунтуванням можна знайти в цій статті InfoQ тут: infoq.com/articles/websocket-and-http2-coexist
мантрид

151

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

PUSH_PROMISE(розмовно відомий як серверний поштовх) тут не проблема. Це просто оптимізація продуктивності.

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

Перш за все, це є бі-ді. Просто прочитайте вступ до розділу потоків :

"Потік" - це незалежна двонаправлена ​​послідовність кадрів, що обмінюються між клієнтом і сервером у межах HTTP / 2 з'єднання. Потоки мають кілька важливих характеристик:

Одне з'єднання HTTP / 2 може містити декілька паралельно відкритих потоків з перемежуванням кадрів кінцевої точки з декількох потоків.

Потоки можуть встановлюватися та використовуватися в односторонньому порядку або спільно використовуватися клієнтом або сервером.

Потоки можуть бути закриті будь-якою кінцевою точкою.

Статті як це (пов'язані в іншу відповідь) не праві про цей аспект HTTP / 2. Кажуть, це не біді. Подивіться, є одне, що не може статися з HTTP / 2: Після того, як з'єднання буде відкрито, сервер не може ініціювати звичайний потік, а лише push-stream. Але як тільки клієнт відкриває потік, надсилаючи запит, обидві сторони можуть в будь-який час надсилати кадри DATA через стійкий сокет - повний bidi.

Це не сильно відрізняється від websockets: клієнт повинен ініціювати запит на оновлення websocket і до того, як сервер також може надсилати дані через.

Найбільша відмінність полягає в тому, що, на відміну від websockets, HTTP / 2 визначає власну семантику мультиплексування: як потоки отримують ідентифікатори та як кадри несуть ідентифікатор потоку, на якому вони перебувають. HTTP / 2 також визначає семантику управління потоком для пріоритетності потоків. Це важливо для більшості реальних програм bidi.

(Ця неправильна стаття також говорить про те, що стандарт Websocket має мультиплексування. Ні, це не так. Це не дуже важко знайти це, просто відкрийте Websocket RFC 6455 і натисніть ⌘-F і введіть "мультиплекс". Після того, як прочитаєте

Протокол призначений для розширення; майбутні версії, ймовірно, введуть додаткові поняття, такі як мультиплексування.

Ви побачите, що існує розширення для проекту мультиплексування Websocket 2013 року . Але я не знаю, які браузери, якщо такі є, підтримують це. Я б не намагався будувати свій SPA webapp на задній частині цього розширення, особливо при надходженні HTTP / 2, підтримка ніколи не надійде).

Мультиплексування - це саме та річ, яку вам зазвичай доводиться робити кожен раз, коли ви відкриваєте веб-розетку для bidi, скажімо, для живлення реально оновлюваного додатка для однієї сторінки. Я радий, що це у специфікації HTTP / 2, про яку потрібно подбати раз і назавжди.

Якщо ви хочете знати, що HTTP / 2 може зробити, просто подивіться на gRPC. gRPC реалізований через HTTP / 2. Подивіться конкретно на параметри напів- та повного дуплексного потоку, які пропонує gRPC. (Зверніть увагу, що gRPC зараз не працює в браузерах, але це насправді тому, що браузери (1) не піддають кадр HTTP / 2 клієнтському javascript, і (2) взагалі не підтримують трейлери, які використовуються в специфікація gRPC)

Де веб-розетки все-таки мають місце? Найбільше - це бінарні дані, що надсилаються на сервер. HTTP / 2 дозволяє бінарні дані, що відштовхуються сервером, і> браузер, але вони не піддаються дії в JS браузера. Для таких програм, як штовхання кадрів аудіо та відео, це привід використовувати веб-розетки.

Редагувати: 17 січня 2020 року

З часом ця відповідь поступово піднімалася до вершини (що добре, оскільки ця відповідь більш-менш правильна). Однак все ще є випадкові коментарі, які говорять про те, що це неправильно з різних причин, як правило, пов’язаних з деякою плутаниною щодо PUSH_PROMISEтого, як насправді споживати сервер, орієнтований на повідомлення -> клієнтське натискання в одному додатку сторінки. Крім того, у веб-переглядачі є випадок використання веб-сокетів, який є бінарними даними, висунутими сервером. Для текстових даних, включаючи JSON, не використовуйте веб-розетки, використовуйте SSE.

Для резюме: протокол HTTP / 2 є повним бі-ді. Однак сучасні веб-браузери не піддають рамковому протоколу HTTP / 2 протокол JavaScript . Незважаючи на те, що якщо ви робите кілька запитів одного і того ж походження через з'єднання HTTP / 2, під кришкою весь цей трафік стає мультиплексованим на одному з'єднанні (і це те, що нас хвилює!).

Отже, якщо вам потрібно створити додаток для чату в реальному часі, скажімо, де вам потрібно транслювати нові чатові повідомлення всім клієнтам у чаті, які мають відкрите з'єднання, ви можете (і, мабуть, повинні) це зробити без веб-розеток.

Ви б використовували події, надіслані сервером, щоб підштовхувати повідомлення вниз, а " Вибрати api" для надсилання запитів. Події, надіслані сервером (SSE) - маловідомий, але добре підтримуваний API, який відкриває потік сервер-клієнт, орієнтований на повідомлення. Хоча він не схожий на клієнтський JavaScript, під кришкою браузера ваш браузер (якщо він підтримує HTTP / 2) повторно використовувати одне TCP-з'єднання для мультиплексування всіх цих повідомлень. Немає втрати ефективності, і насправді це виграш над веб-розетками. Вам потрібно кілька потоків? Відкрийте кілька джерел подій! Вони будуть автоматично мультиплексовані для вас.

Окрім того, що ефективніше використання ресурсів та менша початкова затримка, ніж рукостискання веб-розетки, події, надіслані сервером, мають і приємне властивість: вони автоматично відступають і працюють над HTTP / 1.1. Але коли у вас є з'єднання HTTP / 2, вони працюють надзвичайно добре.

Ось хороша стаття з прикладом у реальному світі щодо реалізованого SPA.


21
Ця відповідь частково не погоджується з іншими, включаючи прийняту, і це також найкраща відповідь, оскільки заснована на прямих джерелах.
судо

7
Я повністю згоден з цією відповіддю та коментарем. HTTP / 2 є двоспрямованим в потоці.
Мартін Мізер

3
Насправді правильна відповідь, хлопець потрудився перевірити джерела та реальний додаток (grpc)
Володимир Акопян

1
У веб-розетках сервер не може почати натискати довільні байти, поки клієнт не ініціює запит на оновлення веб-сокета, але тоді він може натиснути в будь-який час. У HTTP / 2 сервер не може починати натискання байтів, поки клієнт не ініціює з'єднання для передачі даних, але тоді він може в будь-який час натискати байти. У чому полягає функціональна різниця? Як я вже зазначив, здатність PUSH_PROMISE - це червона оселедець. Це не причина, чому HTTP / 2 є заміною веб-сокетів. Це лише незначна оптимізація продуктивності. Це не має нічого спільного з серцем HTTP / 2, що є потоком bidi.
масонник

1
Ця відповідь просто неправильна. Це плутає стільки аспектів, що їх легко заплутати. Однак суть справи полягає в тому, що потоки HTTP / 2 "bidi" керуються запитом-відповіддю (і обмежені в кількості), тоді як протокол WebSockets - це протокол bidi, заснований на істинному повідомленні (не заснований на запиті-відповіді, крім фази рукостискання). Це величезна різниця, яку неможливо подолати просто неправильним прочитанням специфікації (як це ненавмисно здається @masonk).
Міст

64

Я кажу Nay ( Websockets не є застарілим ).

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

тобто (з чернетки HTTP2):

Посередник може отримувати натискання від сервера і вирішувати не пересилати їх клієнту . Іншими словами, про те, як використовувати висунуту інформацію, залежить від цього посередника. Так само посередник може вирішити робити додаткові поштовхи до клієнта, без жодних дій, які вживаються сервером.

Отже, HTTP / 2 Push не може замінити WebSockets.

Крім того, через деякий час HTTP / 2 з'єднання закриваються.

Це правда, що стандарт говорить, що:

З'єднання HTTP / 2 є стійкими. Для найкращої продуктивності очікується, що клієнти не закриватимуть з'єднання, поки не буде встановлено, що подальше спілкування з сервером не потрібно (наприклад, коли користувач переходить від певної веб-сторінки) або поки сервер не закриє з'єднання.

Але ...

Серверам рекомендується підтримувати відкриті з'єднання якомога довше, але їм дозволено припиняти роботи в режимі очікування . Коли будь-яка кінцева точка вирішує закрити TCP-з'єднання транспортного рівня, кінцева кінцева точка ДОЛЖНЯ спочатку надіслати кадр GOAWAY (Розділ 6.8), щоб обидві кінцеві точки могли надійно визначити, чи були раніше відправлені кадри оброблені та витончено виконати або завершити будь-які необхідні завдання.

Навіть якщо одне і те ж з’єднання дозволяє підштовхувати вміст, поки він відкритий, і навіть якщо HTTP / 2 вирішує деякі проблеми продуктивності, що вводяться в режимі "підтримка" HTTP / 1.1 "... З'єднання HTTP / 2 не залишаються відкритими безстроково .

Також веб-сторінка не може ініціювати з'єднання HTTP / 2 після закриття (якщо тільки ми не повернемося до довгої тяги, тобто).

EDIT (2017, два роки пізніше)

Реалізація HTTP / 2 показує, що кілька вкладок / вікон браузера поділяють одне з'єднання HTTP / 2, тобто pushніколи не буде відомо, до якої вкладки / вікна належить, виключаючи використання pushв якості заміни Websockets.

EDIT (2020)

Я не впевнений, чому люди почали заперечувати відповідь. Якщо що-небудь, роки з моменту опублікування відповіді довели, що HTTP / 2 не може замінити WebSockets і не був призначений для цього.

Зазначено, що HTTP / 2 може використовуватися для тунельного підключення WebSocket, але для цих тунельованих з'єднань все ще потрібен протокол WebSocket, і вони впливатимуть на поведінку контейнера HTTP / 2.


4
WS-розетки також не залишаться відкритими назавжди. Відмінності - потоки; HTTP / 2 надає вам кілька потоків потоків, що означає контроль потоку на сервері дуже різний і часто без замкнутий. WS (як протокол) повинен мати нерегульовану вхідну обробку. Контроль потоку реалізується вище стека. Щодо безпеки та цілісності сервера, HTTP / 2 набагато кращий, ніж WS.
облігація

3
@bond, я погоджуюся, що HTTP / 2 має багато переваг як транспортний рівень (обмін одним з'єднанням на багатьох вкладках браузера - лише один приклад). Однак він не розроблений як комунікаційний рівень . Це функціональне питання. Обидва протоколи відповідають різним потребам. тобто реалізація sshтерміналу у браузері - це легкий під час використання Websockets. Це був би загальний головний біль на HTTP / 2, особливо якщо відкрито більше однієї вкладки. Крім того, що робити, якщо браузер (або один із HTTP / 2 проксі) закрив з'єднання? Чи може клієнт просто припустити, що нових даних немає? ми повертаємось до опитування.
Міст

1
Веб-переглядач може так само легко закрити ваше WS-з'єднання. Це життя з будь-якими мережами. Якщо чесно, мультиплексування в HTTP / 2 є надмірним. Протокол справді не потребував цього. Відкриваючи кілька потоків, ви починаєте виникати проблеми з буферами TCP, що обмежують пропускну здатність. Я погоджуюся з вами, що WS кращий у тому, що робить, ніж HTTP / 2. По суті, WS - це те, що потребує значного контролю вищого рівня, щоб запобігти користувачам робити погані речі.
облігація

2
Цитуючи дядька Бена (Людина-павук): "Пам'ятайте, з великою силою настає велика відповідальність". Так, @bond, ти дуже прав. Веб-розетки, будучи дуже «сировинним» протоколом, вимагають більш відповідальної розробки сервера. І так, WS можна закрити так само легко, як HTTP / 2, але WS підтримує oncloseзворотний дзвінок, тому опитування не потрібно. Щодо мультиплексування, я думаю, що це була необхідність, а не вибір. keep-aliveне вдалося, і єдиним способом уникнути "перших ліній" результативності було ризикувати мультиплексування. Час покаже :)
Myst

1
З точки зору дизайну сервера вихідний мультиплексування є складною і дорогою проблемою. Це вимагає механіки IO для внутрішнього опитування, що дорого, як пекло. Якщо ви не передаєте потокові великі документи, мультиплексування навіть не буде функціонувати, тому що запит, ймовірно, відповів і завантажився повністю внутрішньо, перш ніж друга стане доступною, і мультиплексування не запуститься. RTMP має вихідний мультиплексування, але це робить лише сервер Adobe. Дивно, наскільки HTTP / 2 близький до RTMP.
облігація

39

Відповідь - ні. Мета між двома дуже різняться. Існує навіть RFC для WebSocket через HTTP / 2, який дозволяє здійснювати безліч з'єднань WebSocket через одну трубу HTTP / 2 TCP.

WS через HTTP / 2 буде грою збереження ресурсів, скорочуючи час на відкриття нових з'єднань і дозволяючи отримати більше каналів зв'язку без додаткових витрат більше сокетів, м'яких IRQ та буферів.

https://tools.ietf.org/html/draft-hirano-httpbis-websocket-over-http2-01


Це дивовижно! Чи є публічний приклад клієнта Javascript, який реалізував це? Я не можу знайти жодного прикладу. Що мені потрібно було зробити? Це хороший ресурс? undertow.io/blog/2015/04/27/An-in-depth-overview-of-HTTP2.html
RaisinBranCrunch

Хтось знає джерело вищезазначених тверджень про 1) знаходження довжини заголовка, 2) нижній обшивки назв полів?
Пім Хайден

@PimHeijden для виявлення довжини заголовка в HTTP / 1.x вимагає прокручування всіх байтів, які шукають 4-байтовий кінцевий маркер. Це дуже дорого. Неіснуючість імен полів також означає, що будь-яка відповідність поля повинна бути виконана як для верхньої, так і нижньої версії символів. Для цього потрібні знання всього діапазону у верхньому та нижньому регістрі для перевірки. У 2.x ви можете припустити, що вони малі.
облігація

@RaisinBranCrunch Ви нічого не можете керувати цим Javascript. Браузер робить все за вас.
облігація

@bond В даний час я використовую HTTP / 2 з Nginx і proxy_pass для надсилання з'єднань веб-сокетів на сервер сокет, але коли у мене є один користувач, який відкриває кілька вкладок на веб-сайті, сервер сокет розглядає його як кілька підключень. Я б припустив, що якщо HTTP / 2 є мультиплексуванням з'єднань через одну трубу TCP, сервер розглядає це як одне з'єднання. Це неправильно? Чи є спосіб переконатися, що сервер не робить зайвих непотрібних з'єднань?
RaisinBranCrunch

23

Ну, щоб процитувати цю статтю InfoQ :

Ну, відповідь явно ні, з простої причини: Як ми вже бачили вище, HTTP / 2 вводить сервер Push, який дозволяє серверу проактивно відправляти ресурси в кеш-пам'ять клієнта. Однак це не дозволяє пересувати дані до самого клієнтського додатку. Натискання сервера обробляються лише браузером і не спливають до коду програми, тобто немає API для програми, щоб отримувати сповіщення про ці події.

І тому натискання HTTP2 справді щось середнє між вашим браузером і сервером, тоді як Websockets дійсно відкриває API, які можуть використовуватися як клієнтом (javascript, якщо його працює у браузері), так і кодом програми (працює на сервері) для передачі даних у реальному часі.


5

Обмін повідомленнями та просте потокове відео (не аудіо, потокове відео) можна здійснювати як через Http / 2 мультиплексування, так і через WebSockets. Таким чином, є певне перекриття, але WebSockets мають чітко встановлений протокол, багато фреймворків / API та менше заголовків накладних витрат. Ось приємна стаття по темі .


2

Буде реалізація WebSocket в HTTP / 2. https://tools.ietf.org/html/rfc8441


Ні, там не буде ... З'єднання WebSocket буде налаштовано через HTTP / 2, але HTTP / 2 не замінить протокол, і не застаріє.
Міст

@Myst Я це сказав?
Дзінтарс

2
Ні, ти цього не сказав, я. Ви писали, що в HTTP / 2 буде реалізація WebSocket, яка IMHO здавалася занадто короткою і дещо оманливою через відсутність важливих деталей.
Міст

2

Поки що квітень 2020 року, HTTP / 2 не робить WebSockets застарілими. Найбільша перевага WebSockets над HTTP2 полягає в тому, що

HTTP/2 works only on Browser Level not Application Level

Означає, що HTTP / 2 не пропонує такого JS API, як WebSockets, для дозволу спілкування та передачі якихось JSON або інших даних на сервер безпосередньо з програми (наприклад, веб-сайт). Отже, наскільки я вважаю, HTTP / 2 зробить WebSockets застарілими лише тоді, коли він почне пропонувати такі API, як WebSockets, щоб спілкуватися з сервером. Поки це лише оновлена ​​та швидша версія HTTP 1.1.


2

Станом на сьогодні ні.

HTTP / 2, порівняно з HTTP, дозволяє підтримувати зв’язок із сервером. Звідти ви можете мати декілька потоків даних одночасно. Намір полягає в тому, що ви можете одночасно натискати кілька речей, навіть не вимагаючи від цього клієнта. Наприклад, коли браузер запитує index.html, сервер, можливо, також захоче натиснути index.cssі index.js. Браузер не запитував цього, але сервер може надати його, не запитуючи, оскільки він може припустити, що вам захочеться через кілька секунд.

Це швидше , ніж HTTP / 1 альтернативи отримання index.html, аналізу його, виявивши , що потрібно index.jsі index.cssі потім будує 2 інших запитів для цих файлів. HTTP / 2 дозволяє серверу проштовхувати дані, які клієнт навіть не вимагав.

У цьому контексті він схожий на WebSocket, але насправді не за дизайном. Передбачається, що WebSocket дозволяє дозволити двосторонній зв'язок, подібний до TCP-з'єднання або послідовного з'єднання. Це розетка, де обидва спілкуються один з одним. Крім того, головна відмінність полягає в тому, що ви можете надсилати будь-які довільні пакети даних у необроблених байтах, не інкапсульованих у протоколі HTTP. Поняття заголовків, шляхів, рядків запитів трапляються лише під час рукостискання, але WebSocket відкриває потік даних.

Інша відмінність полягає в тому, що ви отримуєте набагато більш чітко налаштований доступ до WebSocket в Javascript, тоді як з HTTP ним керує браузер. Все, що ви отримуєте за допомогою HTTP - це все, що ви можете вмістити XHR/ fetch(). Це також означає , що браузер буде дістатися до перехоплювати і змінювати HTTP заголовки без вас в змозі контролювати (наприклад , Origin, Cookiesі т.д.). Також те, що HTTP / 2 здатний натиснути, надсилається до браузера. Це означає, що JS не завжди (якщо і коли-небудь) знає, що справи підштовхуються. Знову ж, це має сенс index.cssі index.jsтому, що браузер буде кешувати його, але не стільки для пакетів даних.

Це справді все в назві. HTTP розшифровується як протокол передачі HyperText. Ми орієнтовані на концепцію передачі активів. WebSocket - це створення з'єднання з сокетом, в якому бінарні дані передаються навколо двосторонньо.


Те, що ми насправді не обговорюємо, - це SSE (Server-Sent Events). Переміщення даних до програми (JS) не є метою HTTP / 2, але це для SSE. SSE дійсно зміцнюється за допомогою HTTP / 2. Але це не справжня заміна для WebSockets, коли важливими є самі дані, а не змінні кінцеві точки, що досягаються. Для кожної кінцевої точки в WebSocket створюється новий потік даних, але з SSE він поділяється між уже існуючим сеансом HTTP / 2.


Узагальнені тут цілі кожного:

  • HTTP - відповідь на запит одним об’єктом
  • HTTP / 2 - відповідь на запит із кількома активами
  • SSE - відповідь однонаправленим текстовим потоком (UTF-8) подій
  • WebSocket - Створення двонаправленого потоку бінарних даних
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.