Ефективна імплементація SSE. Переваги та виклики

💡 Усі статті, обговорення, новини про Front-end — в одному місці. Приєднуйтесь до Front-end спільноти!

Усім привіт! Мене звати Марія Образцова, я Front-end розробниця в бізнесі FORMA продуктової IT-компанії Universe Group, що створює мобільні застосунки та вебплатформи для підвищення якості життя людей. FORMA — це бізнес, який створює SaaS для роботи з документами. Свій професійний шлях я розпочала три роки тому. За цей час здобула чималий досвід в розробці та власні вдалі кейси.

Протягом усього життя нашого продукту ми встигли імплементувати різні підходи до комунікації клієнта з сервером: Long-polling, Short-polling та Server Side Events (SSE). Під час нещодавньої реалізації останнього з них — SSE, я не знайшла предметного порівняння усіх трьох методів. Є багато статей, де описуються їхні плюси та мінуси на теоретичному рівні, але мені не траплялись практичні результати порівнянь — час отримання клієнтом інформації з сервера, підводні камені імплементацій тощо. Тому вирішила виправити це своїм текстом.

У статті буде трішки теорії про кожен з методів (плюси, мінуси та підводні камені з досвіду нашого продукту), безпосередньо практична частина — результати кожного методу у графіках, а також короткі підсумки.

Матеріал буде корисним для розробників та розробниць, що у себе на проєкті так чи інакше забирають інформацію з сервера (або саме ухвалюють рішення, яким чином це робити). А також для тих, хто хоче дізнатись трошки більше про комунікації клієнт-сервер для загального розвитку.

Історія версій, або Наші висновки на шляху розв’язання проблеми

Одна з основних функціональностей продукту — конвертація файлів з PDF в інші формати та навпаки. Безпосередньо конвертація виконується стороннім сервісом, з яким комунікує Back-end.

Отже, основне завдання Front-end частини — дочекатися завершення конвертації (тобто відповіді від Back-end), забрати готовий файл та передати його користувачеві якомога швидше.

Далі перейдемо до методів, які ми випробували для цього.

Long-polling

Першою ітерацією був Long-polling — метод, де клієнт відправляє звичайний HTTP-запит, а сервер тримає цей запит відкритим, поки у нього не зʼявиться відповідь (у нашому випадку це закінчення конвертації) або не витече час зʼєднання (timeout). Якщо клієнт не отримав успішну відповідь, то відразу після закриття старого запиту він кидає наступний.

Схематичне зображення Long-polling

Спрощена імплементація на нашому продукті:

/** * @description Attempts to retrieve a converted file from the backend *   1. Send request to backend to get the converted file with the provided fileId and format
2. If the conversion process has failed, throw an error
3. If the file is successfully converted, return the result
4. If a timeout error occurs and attempt count is less than 2, increment attempt count and retry
5. If a timeout error occurs and attempt count is 2 or more, reset attempt count to 0 and throw the error
6. If any other error occurs, throw the error 
*/
  const waitForFileConvertLongPolling = async (
    fileId: string,
format: InternalFileType,
    attempt = 0
  ) => {
    try {
      const result = API.files.getConvertedFile(fileId, format)

      if (result.processing_status === 'FAILED') { 
        throw new Error()
      } 
      return result
    } catch (e) {
      if (axios.isAxiosError(e) && e.message.includes("timeout")) {
        if (attempt < 2) {
          attempt++;
          return waitForFileConvertLongPolling(fileId, format, attempt);
        } else {
          attempt = 0;
          throw e;
        }
      }
      throw e;
    }
  };

Плюси такого підходу:

  • Легка імплементація. Це прості HTTP-запити, які відправляються з певним інтервалом.
  • Майже real-time отримання інформації. Оскільки сервер тримає зʼєднання відкритим, клієнт миттєво отримує інформацію. Єдиний виняток — якщо потрібна інформація (у нашому випадку результат конвертації) надходить в момент встановлення підключення з сервером. Тоді буде несуттєва затримка.
  • Через те, що це прості HTTP-запити, цей метод підтримується всіма браузерами.

Мінуси методу:

  • Ресурсозатратно. Метод вимагає від сервера тримати підключення для кожного клієнта відкритим протягом достатньо довгого часу, що потребує великих ресурсів.
  • Високий ризик краша сервера. З попереднього пункту зрозуміло, що занадто стрімке масштабування кількості зʼєднань та/або поганий попередній розрахунок необхідних ресурсів можуть призвести до падіння сервера та, отже, всього вебзастосунку.
  • Неоптимальне використання ресурсів. Зʼєднання підтримуються відкритими та споживають ресурс, навіть якщо фактичного обміну інформацією немає.

Чому відмовились? Через регулярні падіння сервера.

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

Також не забуваємо, що сам по собі Long-polling не зовсім оптимально використовує ресурси.

Ці проблеми (і суботні повідомлення про те, що сайт разом з Back-end знову лежать) змусили нас відмовитись від такого методу та перейти до наступного етапу для продукту — Short-polling.

Short-polling

Наступним проміжним етапом був Short-polling. Його відмінність від попереднього методу полягає в тому, що сервер одразу віддає клієнту відповідь — готовий файл до завантаження чи ще ні. Клієнт, своєю чергою, відправляє наступний запит із затримкою (на відміну від Long-polling, де наступний запит летить одразу), щоб уникнути надмірного навантаження на Back-end — вірогідність того, що файл конвертується за одну мілісекунду, дуже мала.

Схематичне зображення Short-polling

Спрощена імплементація на нашому продукті:

/** * @description wait for the file (with the provided fileId) to convert 1. Send request to backend to know if the file is already converted
2. If file is already converted, return result
3. If not, wait 3 sec and send request again
4. Try to get success status for 30 attempts
5. If all 30 tries failed, throw error and set attempt to 0 
*/
const waitForFileConvertShortPolling = async (
    fileId: string,
    format: InternalFileType,
    attempt = 0
  ) => {
    try {
      const result = await API.files.getConvertedFile(fileId, format)

      if (result.processing_status === 'FAILED') {
 throw new Error('converting failed') 
      } 
      return result
    } catch (e) {
      //@ts-ignore
      if (e.message === "converting failed") {
        throw e;
      }

      if (attempt < 30) {
        attempt++;

        await wait(3000);
        return waitForFileConvertShortPolling(fileId, format, attempt);
      }
      attempt = 0;
      throw e;
    }
  };

Плюси такого підходу:

  • Легка імплементація. Аналогічно Long-polling, це також прості HTTP-запити, які відправляються клієнтом з незначним інтервалом.
  • Через свою простоту цей метод підтримується усіма браузерами.
  • Менш ресурсомісткий у порівнянні з Long-polling. Серверу потрібно відразу повернути відповідь на запит, а не тримати відкрите зʼєднання протягом певного часу, що зменшує навантаження на нього.

Мінуси методу:

  • Може призвести до перевантаження Back-end постійними запитами. Запити, у порівнянні з запитами Long-polling, не забирають багато ресурсів сервера. Однак їхня кількість при необережному поводженні (наприклад, відсутність затримки між запитами) та великій кількості користувачів може бути подібна до DDoS-атаки на сайт.
  • Можлива затримка інформації. Запити відправляються з деяким інтервалом (на нашому продукті, наприклад, це було 3 секунди). Тому результат конвертації може досягти клієнта на 3 секунди (в гіршому випадку) пізніше, ніж цей результат буде готовий для відправлення сервером. Затримка також може зростати, особливо якщо Back-end перевантажений через вищезазначений мінус.

Чому відмовились? Через неоптимальну кількість часу, потрібну для отримання файлу. Часто траплялись випадки, коли файл конвертувався швидше, ніж Front-end був готовий його забрати. Тобто Back-end був готовий повернути файл раніше, ніж клієнт встиг відправити повторний запит через ці 3 секунди.

Тож настав час переходити до наступного етапу життя продукту — Server Side Events (SSE).

Але перед цим дам відповідь на питання — чому не WebSocket?

Задачу миттєво забрати готовий файл з сервера після закінчення конвертації можна було б також вирішити за допомогою WebSocket.

WebSocket — це двосторонній канал комунікації сервер-клієнт, що дозволяє обмінюватись інформацією у реальному часі.

Одна з ключових відмінностей від SSE полягає в підтримці двосторонньої комунікації, що означає: і сервер, і клієнт можуть відправляти інформацію (на відміну від SSE, де клієнт лише приймає її). Також важливо врахувати, що для управління вебсокетами потрібно мати додатковий сервер, бо ця технологія не використовує звичайні HTTP-протоколи.

Оскільки клієнту потрібно лише забирати інформацію про файл, тобто тільки слухати сервер, WebSocket у нашому випадку перетворився б на overengineering та залучення великих, але зайвих ресурсів.

Схематичне зображення WebSockets

Server Side Events

Фінальною стадією отримання файлу з сервера на нашому продукті став SSE.

Server Side Events (SSE) — це технологія, яка дозволяє серверу надсилати до клієнта повідомлення в режимі реального часу. На відміну від Long- та Short-polling, клієнт та сервер одноразово встановлюють зʼєднання (часто це відбувається під час ініціалізації застосунку), і клієнт підписується на оновлення з цього каналу. Після цього сервер може відправляти оновлення без зайвих запитів з боку клієнта.

Тобто, як тільки наш файл конвертується, сервер відправляє сповіщення з інформацією про файл, і клієнт в той самий момент отримує це сповіщення та запускає відповідну обробку інформації (наприклад, звантаження файлу користувачу).

Схематичне зображення SSE

Спрощена імплементація на нашому продукті:

// this code is running while app is initializing
const eventSourceRef = useRef<EventSource>(); 
React.useEffect(() => {
  if (!eventSourceRef.current) { 
     eventSourceRef.current = new EventSource( "absolute-url-for-sse" ); 
  }
}, []);

const waitForFileConvertSSE = (): Promise<ConvertedFile> => {
  return new Promise((resolve, reject) => {
    if (eventSourceRef.current) {
       eventSourceRef.current.onmessage = (event) => {
         // handle downloading file
       };
       eventSourceRef.current.onerror = (error) => {
         // handle error (for example, show fail-popup)
       };
   }
  })
};

Плюси такого підходу:

  • Відсутність додаткових запитів на сервер. Після встановлення зʼєднання клієнт просто очікує на повідомлення від сервера.
  • Відсутність необхідності регулярно перевстановлювати зʼєднання, як це було з Long-polling. SSE не має timeout, які потрібно обробляти й, знову ж таки, кидати нові запити.
  • Одна з головних переваг цього методу полягає у real-time отриманні інформації з сервера — ніяких затримок при повторних відсиланнях запитів.

Мінуси:

  • Потребує додаткової імплементації на стороні Back-end. На відміну від двох попередніх методів, які по суті є простими HTTP-запитами, які клієнт відправляв з певною затримкою, SSE вимагає імплементації як зі сторони Front-end, так і зі сторони Back-end. Варто звернути увагу, що додаткова імплементація на сервері — це не означає підняти додатковий сервер, на відміну від WebSocket.

Розгляньмо також і підводні камені.

Ускладнена логіка балансування навантаження. Після завершення конвертації готовий файл зберігається у базі даних. При використанні HTTP-запитів (наприклад, Short-polling) ми звертаємось до Back-end з запитом «Чи готовий конвертований файл?». Back-end відправляє запит до бази даних для пошуку готового файлу і повертає відповідь. Тобто запит і отримання відповіді відбувається на одному і тому ж Back-end.

У випадку SSE Front-end-1 підтримує постійне з’єднання з Back-end-1, але повідомлення про готовність файлу може прийти до Back-end-2. Відповідно, повідомлення ніколи не буде доставлено до Front-end-1, оскільки Back-end-1 не отримає його, а з Back-end-2 з’єднання з Front-end-1 відсутнє. Тому для SSE потрібно передбачити «прошарок» на рівні Back-end та інфраструктури (у нашому випадку це Redis), який буде відповідальний за розсилання сповіщень всім Back-ends про готовність файлу.

Верифікація refresh token. Оскільки SSE встановлює зʼєднання один раз і довго його утримує, можливо, з’явиться потреба оновлення refresh token протягом цього часу. Конкретний план дій може варіюватись залежно від імплементації авторизації в кожному окремому продукті, проте важливо не забувати про цей аспект.

А тепер — до результатів практики

Основне завдання, яке я ставила перед собою в цій статті: забрати результат конвертації з Back-end якомога швидше. Виміряти успіх цієї задачі дуже просто за допомогою графіків. Для порівняння швидкості цих підходів я провела невеликий експеримент — взяла результати конвертації 500 файлів для усіх трьох підходів.

Тож представляю вам графік, де синя крива — це результати Short-polling, червона крива — результати Long-polling, а зелена — результати SSE. Вісь Y — це час конвертації у секундах, вісь Х — порядковий номер файлу (від 1 до 500).

Графік 1

Як явно бачимо з графіка вище, SSE швидше повертає результат.

Якщо дивитись за середнім часом конвертації, для SSE він становить 15,63 секунди, для Short-polling — 33,17 секунди, для Long-polling — 32,9 секунди.

Графік 2: Середній час конвертації для Server Side Events (червона лінія) — 15,63 секунди

Графік 3: Середній час конвертації для Short-polling (червона лінія) — 33,17 секунди

Графік 4: Середній час конвертації для Long-polling (помаранчева лінія) — 32,9 секунди

Підсумуємо

Long-polling легкий в імплементації та віддає інформацію майже в real-time, якщо тільки сервер не отримав інформації під час реконекта до клієнта. При цьому він дуже ресурсомісткий та має високий ризик краша застосунку, якщо необережно поставитись до навантаження (наприклад, при швидкому масштабуванні кількості юзерів на сайті).

Short-polling також дуже легкий в імплементації та менш ресурсомісткий у порівнянні з long-polling, оскільки браузеру не треба тримати зʼєднання довго. Але існує великий шанс затримки інформації через відправлення запитів з інтервалом. Також цей метод збільшує навантаження на Back-end, бо ми відправляємо велику кількість запитів, що може призвести до краша застосунку або до збільшення ресурсоспоживання.

Server Side Events мають велику перевагу у швидкості, адже інформація відправляється з сервера до клієнта без жодних затримок. Це легко побачити в результатах експерименту — середній час конвертації для SSE удвічі менший, ніж для двох попередніх методів. Серед переваг методу можна назвати відсутність додаткових запитів та часу на реконект. До мінусів та підводних каменів належать додаткова імплементація на частині Back-end, а також ускладнена логіка балансування навантаження з погляду інфраструктури.

Тож, якщо порівнювати усі три технології за швидкістю роботи, SSE, вочевидь, перемагає. Та це не означає, що усім проєктам треба терміново запровадити SSE замість Long- та Short-polling.

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

Також раджу замислитись, чи вартий цього SSE, якщо на продукті взагалі не відіграє ролі швидкість отримання інформації.

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

👍ПодобаєтьсяСподобалось17
До обраногоВ обраному5
LinkedIn
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

А можна більше деталей які конкретно ресурси сервера забирає Long Polling і чим він може бути більш ресурсозатратним ніж Short Polling? Важко собі уявити як тримання активного з’єднання може забирати більше ресурсів ніж постійна обробка нових реквестів від великої кількості клієнтів. Ось наприклад в сусідній статті більше детальний аналіз навантаження і там все навпаки: dou.ua/...​/topic/51688/?from=fptech

Запити, у порівнянні з запитами Long-polling, не забирають багато ресурсів сервера.
Менш ресурсомісткий у порівнянні з Long-polling. Серверу потрібно відразу повернути відповідь на запит, а не тримати відкрите зʼєднання протягом певного часу, що зменшує навантаження на нього.

Також було б дуже цікаво зрозуміти про які креші йде мова, з чим вони пов’язані, це просто якесь фізичне обмеження на кількість активних підключень, типу порти закінчились? Якщо це CPU то все просто буде повільним, якщо це велика кількість пам’яті то вона буде свапнута, креші абсолютно неочевидні на перший погляд.

Високий ризик краша сервера. З попереднього пункту зрозуміло, що занадто стрімке масштабування кількості зʼєднань та/або поганий попередній розрахунок необхідних ресурсів можуть призвести до падіння сервера та, отже, всього вебзастосунку.

Я думал, long polling вымер лет 15 назад. Ан нет...

Перейшов тому що розкажуть щось новеньке про SIMD:)

Перш за все, дякую за статтю

> а також ускладнена логіка балансування навантаження з погляду інфраструктури

З вебсокетом є та ж сама проблема, але чомусь бібліотек для вебсокетів в рази більше, і часто умовний redis pubsub як бекенд для того вже з коробки йде.

Більше хотілося би почути про підводні камені такі як обмеження браузерів, хедери, кастомні хедери (а точніше проблеми з ними), а також про те які є зовнішні js бібліотеки для роботи з SSE, що можуть вирішити дещо з цього.

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

Дякую за ідею про підводні камені!
Ідея статті виникла, коли я сама ресьорчила питання оптимального шляху отримання даних з бекенда. Ми запровадили SSE не так давно і поки з підводними каменями не зіштовхнулись, але цю тему варто дослідити.
Можливо, зіштовхнулись, але не знаємо про це 😅

Ми запровадили SSE не так давно і поки з підводними каменями не зіштовхнулись

навіть з відсутністю (у ванільній реалізації) POST реквестів?

ми наразі з SSE юзаємо тільки GET запити (власне, якими ми користувались і з long/short-polling).
Можливо, у майбутньому будемо розширювати юз-кейси і тоді зіштовхнемось з усіма ускладненнями, але наразі поки без них)

коли я сама ресьорчила
ресьорчила
ресьорчила

РЕСЬОРЧИЛА

Наголос підберіть самі :)

if (axios.isAxiosError(e) && e.message.includes("timeout")) {

Без костиля:

import axios, {AxiosError} from 'axios';

const instance = axios.create({
  transitional: {
    clarifyTimeoutError: true
  }
});

try {
  const {data} = await instance.get('https://dummyjson.com/products', {
    timeout: 3
  });

  console.log(data);
} catch(e) {
  if(e?.code === AxiosError.ETIMEDOUT){
    console.log('timeout');
  }
}

> transitional options for backward compatibility that may be removed in the newer versions
теж трохи костильно виглядає враховуючи цей момент

теж трохи костильно виглядає враховуючи цей момент

Ну то «сертифікований» костиль для міграції, який дропнеться як це стане дефолтною поведінкою

дивно, чому SSE х2 краще за long-polling. другий же теж в кращому випадку одраз поверне результат і загалом по ресурсам однаково з SSE. що там тримається з’єднання, що там. загалом можна підлаштувати оптимальний timeout для LP таким, щоб завжди було достатньо одного запиту. Але по конфігурації буде важче, бо обмеження per-endpoint, і треба і на reverse proxy задати, і на фроті мб, і на бекенді підлаштувати. але як наявність з’єднань впливає на швидкість конвертаціЇ?

Мені тож цікаво, я підозрюю може реконекшени грають роль, лонгполінг в теорії це хендшейк щоб потім колись отримати івент, це дорого в принципі хендшейк на кожен івент

Можна не один івент, developer.mozilla.org/...​/docs/Web/API/Streams_API. І хендшейка на кожен реквест там не буде ( якщо http >=2)

Думаю тут проблема у тому, що сам бенчмарк зроблений некоректно. Міряти треба саму комунікацію, а не бізнес логіку.

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

Вона про лоад написала

Ну чого ж це некоректно, історично ж різні підходи отримувати івенти, якраз коректно порівнювати

Погоджуюсь, по факту SEE це той же лонгполінг тільки з гарним інтерфесом. Що перший, що другий породжують проблему великої кількості з’єднань до сервера. Що у першому, що у другому випадку http >=2 згладжуе проблему.

Ну от цей пойнт чим SSE принципово краще за лонгполінг мені не зайшов. Тобто більш сучасно і мабуть на клієнті зручніше але і то і то тримає відкритий конекшн, то якось мені одне на одне. Але я тільки поверхнево тему ковирнув, хз

тут хоч як крути, пулінг робить більше 1 го реквеста, ссе робить 1 реквест що більш оптимально

Це не зовсім так. Все залежить від налаштування таймаутів сервера/кліента. Якщо таймаути короткі SSE також буде обриватись ( як і при лонгполінгу) і потрібно буде робити новий запит ( так часто і роблять, адже інколи корисно синхронізовувати стейт)

все завжди залежить від налаштування, наприклад я можу задати короткий кіп-елайв хедер в реквест, що зробить хттп2 менш єфективним. Чи каже це що хттп2 такий же єфективний як хттп1.1 — ні, але треба буде частіше створювати тсп коннекти. З вашим прикладом теж саме, так, ми можемо зменшити єфективність ссе і зробити її ближче до пулінгу, але в середньому ссе профітніше.

Я тут більше про те, що і лонгпулінг і SSE залежить від рід/райт таймауту, якщо їх сконфігурувати для обох випадків однаково, то помітної різниці у перфоменсі і поведінці ( за умови якщо ми чекаємо всього один івент) не буде. Так як принцип роботи однаковий, тільки SSE це стрім респонса, а пулінг ( ванільний) ні.

як на мене більш корректно порівняти сокети і ссе, а пулінг це просто реквест — респонс

Не зовсім, так як вебсокет двонаправлений та апгрейдить протокол, а SSE, як і пулінг, однонаправлений і пофакту стрімить респонс частинами.

так, це і варто між ними порівнювати, але вони обидва мають схему — відкрили коннект, почали стрімити респонс, можна було б ще описати що ссе спускає тіки текстові дані, а сокети можуть спускати бінарник, також особливості юзання сокетів і ссе на хттп2 та хттп3

Дякую за коментар!
Я взяла саме ці методи для порівняння з точки зору вирішення задачі забрати дані з сервера, тому що сама у не так давно задалась питанням оптимального рішення і було б дуже зручно мати характеристики більшості поширених методів під рукою та в одному місці.
Подумала, що це було б зручно не тільки мені і оформила дослідження в статтю)

Як на мене, люди будуть сьорчити подібні порівняння для того, щоб вирішити конкретну бізнес-задачу, а не за відразу шукати більш технічні нюанси, як кількість конекшенів і тд. Особливо, якщо нема досвіду роботи з sse та сокетами)

Варто звернути увагу, що додаткова імплементація на сервері — це не означає підняти додатковий сервер, на відміну від WebSocket.

— так і для вебсокетів додатковий сервер не треба піднімати

мені корисно, я якраз колупаю, дякую

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

Ваші приклади це щось реакт-специфік чи теоретично socket.io з реактом дружить ок?

У модерному фронтенді я любитель, це в мене просто пет проджект, просто проходив повз...

вебсокет можна підняти на чистому JS, там все дуже просто
це зі сторони сервера потрібно або лібу або розписати все правильно

наскільки я розумію мінус вебсокетів це файрволи, то собі я просто відсилаю на сервер звичайними ріквестами, поки не розібрався з вебсокетами, а так то згоден з тобою

Пані просто пише триповерховий код на реакті а в мене тут якось виходить попроще все. Ну таке, не претендую, я взяв vue, особо не знаю ні те ні інше, то просто цікаво було чи це через реакт так складно чи просто паня ускладнює

наскільки я розумію мінус вебсокетів це файрволи

Чому? Там також конекшн до хабу ініціюється клієнтом. З точки зору TCP там начебто немає відмінностей окрім того що коннекшн не дропається порівняно з http.

Ну я за ці дні рісьорчнув цю тему

В основному ти прав, але чутки про файерволи тож не безпідставні, прикол чи долетить до сервера HTTP Upgrade і чи він обробиться

В основному це один з трьох варіантів — якісь вайфай мережі з кептів порталами, суперпараноїдальні енвайронменти чи просто старі файрволи довебсокетної ери

Загалом в моєму кейсі думаю переживати особо не варто )

У нас якось був прикол з Київстаром, що на мобільному інтернеті у деяких містах різався коннект по вебсокетах. Фіксили з їхньою техпідтримкою. Так що тут дійсно всяке буває :)

Підписатись на коментарі