Транспорт: WebSocket, HTTP і повторне підключення
Обмін віджета із сервером чату: адреси, підпротокол rc.v1, формат кадру, коди помилок і закриття, ліміти, повторне підключення з seq й усуненням дублікатів та резервний канал HTTP через SSE і довге опитування.
Ця сторінка описує обмін між віджетом у браузері й сервером чату. Вона потрібна для усунення несправностей (вкладка мережі інструментів розробника), правил проксі й міжмережевого екрана та Content Security Policy.
Важливо: мережевий протокол — інтерфейс між нашим віджетом і нашим сервером. Власні клієнти, що безпосередньо використовують протокол, офіційно не підтримуються; поля можуть розширюватися в межах версії 1. Для власних інтерфейсів використовуйте JavaScript API, для серверних з’єднань — вебхуки та серверний API.
Адреси
- WebSocket:
wss://ws.reactive.chat/rc_wss/ - Резервний канал HTTP, офлайн-форма, завантаження: та сама адреса з
https://, тобтоhttps://ws.reactive.chat/rc_wss/h/…,https://ws.reactive.chat/api/offline/<SITE_KEY>іhttps://ws.reactive.chat/rc_wss/upload/… - Файли віджета:
https://cdn.reactive.chat/
Як віджет знаходить адресу WebSocket:
data-rc-ws-urlу тегу завантажувача,window.ReactiveChatSettings.wsUrlабоReactiveChat('boot', { wsUrl })— якщо задано, діє це значення.- Інакше виводиться з розташування
loader.js:wss://ws.+ останні дві частини домену +/rc_wss/.cdn.reactive.chatстаєwss://ws.reactive.chat/rc_wss/.
Звідси дві пастки:
- Якщо ви надаєте
loader.jsзі свого домену, віджет виводить адресу під вашим доменом. Тоді задайтеdata-rc-ws-url(див. Швидкий старт). - Із двоскладовими закінченнями, як-от
.co.uk, адреса виводиться неправильно. Явно задавайтеdata-rc-ws-url.
Шлях WebSocket не обробляє параметрів запиту.
Встановлення з’єднання
- Момент: віджет підключається не під час завантаження сторінки, а за першої справжньої взаємодії (рух миші, натискання, клавіша, колесо, дотик, фокус). Підключається одразу, якщо вікно чату відкрите чи відкривається, відома розмова відвідувача або є ненадіслані повідомлення. Із
data-rc-connect="load"на будь-якому елементі (зазвичай тегу завантажувача) абоwindow.ReactiveChatSettings.connect = 'load'підключається під час завантаження, як раніше. Правила з часом після перегляду сторінки рахуються від першої взаємодії. - Підпротокол: віджет відкриває
new WebSocket(url, 'rc.v1'), сервер віддзеркалюєrc.v1. Версія протоколу не в адресі, а в кожному кадрі (v: 1). - Лише текстові кадри, UTF-8; один кадр = одне повідомлення. Без стиснення (
permessage-deflateвимкнено на сервері). - Узгодження: після
openвіджет надсилаєinitщонайпізніше за 5 секунд; сервер відповідаєinit_ok. Якщоopenне надходить за 8 секунд, спроба невдала; якщоinit_okнемає за 10 секунд, віджет підключається знову. - Перевірка джерела: сервер порівнює ім’я хоста заголовка
Originз доменами проєкту (Дозволені джерела в обліковому записі). Схема й порт не враховуються; піддомени збігаються (www.your-company.comвідповідаєyour-company.com,notyour-company.com— ні). За невдачі:origin_denied, потім закриття 1008, без повтору. Якщо в проєкті немає домену, перевірки джерела немає — тому завжди додавайте домени.
Формат кадру
Кожне повідомлення в обох напрямках має вигляд:
{ "v": 1, "t": "msg", "id": "01JAB3C4D5E6F7G8H9JKMNPQRS", "ts": 1792500000000, "d": { } }
- v (ціле число, обов’язкове) — версія протоколу, зараз
1. - t (рядок, обов’язковий) — тип повідомлення,
[a-z0-9_]{1,24}. - id (рядок, обов’язковий) — ULID: 26 символів Crockford Base32, лише великі літери. Також ключ усунення дублікатів.
- ts (ціле число, обов’язкове) — мілісекунди від 1970 року, лише для діагностики.
- d (об’єкт, обов’язковий) — корисне навантаження, ніколи
null, порожнє —{}.
Невідомі типи й поля мовчки ігноруються, що зберігає сумісність старих віджетів із новими серверами.
Огляд типів повідомлень
Від віджета до сервера:
- init — реєстрація з’єднання: ключ сайту, ID сеансу, відвідувача, вкладки й розмови, мова, стан згоди, підписана ідентифікація за наявності (
user), контекст сторінки (ctx) й точка відновлення (resume). - msg — повідомлення відвідувача (текст, до 5 вкладень, відповідь на швидкі відповіді чи форми).
- typing — індикатор набору (
start/stop). Вміст поля введення ніколи не передається. - read — прочитано до
seq. - ctx — зміна контексту, наприклад під час навігації SPA або після
identify. - csat — оцінка (великий палець угору/вниз, коментар до 1000 символів).
- upload_req — запит дозволу завантаження (назва, MIME-тип, розмір, SHA-256).
- transcript, forget, consent — листування на пошту, видалення власних даних, надання/відкликання згоди.
- ping — підтримання з’єднання.
Від сервера до віджета:
- init_ok — підтверджені ID, історія, оформлення, функції й ліміти (нижче), результат перевірки особи (
identity.verified). - msg — повідомлення (зокрема повернення власного повідомлення відвідувача з
client_id). - bot_typing, bot_stream — ШІ-асистент думає чи пише;
bot_streamзавжди передає весь видимий текст, щонайчастіше кожні 150 мс. - typing, read, handoff, queue_pos, proactive, conv_list, error, pong.
Коди помилок
Помилка надходить кадром t: "error" із d.code, d.message (англійською, лише для розробників), d.retry (no, immediate, backoff, after_reinit) і за потреби d.retry_after_ms та d.detail. Список закритий; невідомий код обробляється як internal.
- bad_json — недійсний JSON; після трьох випадків закриття 1008.
- bad_envelope — кадр порушує формат (також ULID із відхиленням понад 24 год,
detail.reason: stale_or_future). - unsupported_version — версію неможливо узгодити; закриття 4001.
- unknown_site_key — ключ сайту невідомий, проєкт призупинено чи архівовано; закриття 4002.
- origin_denied — джерело не серед доменів проєкту; закриття 1008.
- visitor_blocked — відвідувача заблоковано; закриття 1008.
- auth_failed — невдала перевірка особи,
detail.reason:no_hash,bad_hash,bad_exp,expired,exp_too_far. Сеанс продовжується анонімно. - not_initialized / already_initialized — повідомлення до
initабо другийinit. - init_timeout — немає
initза 5 с; закриття 4004. - conversation_not_found / conversation_closed
- rate_limited — ліміт частоти; з
retry_after_ms. За повторення в тому самому з’єднанні сервер закриває з 4008. - payload_too_large — кадр понад 64 КіБ.
- msg_too_long — текст понад ліміт тарифу,
detail.max. - unsupported_kind, attachment_invalid
- upload_disabled, upload_too_large, upload_mime_denied, upload_expired
- consent_required — дія потребує згоди.
- dnd_active — активний режим «Не турбувати».
- session_conflict — надто багато з’єднань одного сеансу (понад 3); закриття 4003, вкладка стає веденою.
- internal, unavailable — тимчасово; повтор із затримкою.
Коди закриття
- 1000, 1001, 1006, 1011, 1013, 4004 — віджет підключається знову (із затримкою).
- 1008 — джерело відхилено, повторно недійсний JSON, блокування захистом від зловживань. Без повтору на цій сторінці.
- 4001 — версію неможливо узгодити. Без повтору.
- 4002 — ключ сайту невідомий або проєкт неактивний. Без повтору.
- 4008 — повторне обмеження частоти. Віджет чекає
retry_after_msі підключається знову. - 4003 — конфлікт сеансу; вкладка працює як ведена іншої вкладки.
Ліміти з’єднання
Сервер надсилає визначальні значення в init_ok.limits і init_ok.features:
- heartbeat_ms 25 000 — віджет надсилає
pingчерез 25 с після останнього вихідного повідомлення. - pong_timeout_ms 10 000 — два відсутні
pongспричиняють повторне підключення. - idle_timeout_ms 70 000 — сервер закриває після 70 с без вхідного кадру (1001).
- max_frame_bytes 65 536 — більші кадри:
payload_too_large. - msg_per_10s 20 і frames_per_10s 120 — кошик токенів на з’єднання; понад це —
rate_limited. - reconnect_cap_ms 30 000 — найдовша затримка повторів.
- dedup_window_ms 86 400 000 — 24 години усунення дублікатів.
- features.max_msg_len — символи (кодові точки Unicode) на повідомлення відвідувача: 1000 на Free, 4000 на платних тарифах. Задовгі тексти віджет не надсилає.
- features.max_upload_bytes, features.allowed_mime — див. Ліміти й квоти.
Повторне підключення, порядок, дублікати
- Затримка:
min(30000, 500 × 2^(attempt−1))мс, використовується випадкове значення у верхній половині (спроба 1: 250–500 мс, від спроби 7: 15–30 с). У фонових вкладках утричі довше.retry_after_msсервера — нижня межа. Кількість спроб необмежена; лічильник скидається лише наinit_ok. Якщо браузер повідомляєonline, віджет пробує одразу; якщо офлайн — чекає. - Порядок: кожне повідомлення розмови має безперервний
seqвід 1. Повідомлення показуються заseq, не за часом. Під час перепідключення віджет надсилаєresume.last_seqта до 50 очікуваних ID; сервер доставляє все після цього (до 100 повідомлень, інакшеhas_more) й повторює підтвердження вже отриманих. - Без дублікатів: сервер пам’ятає кожен
idповідомлення 24 години. Повтор не зберігається знову, але отримує те саме підтвердження. «Надіслати знову» у віджеті використовує той самийid. - Стани вихідного повідомлення:
pending→sent→delivered(повернення із сервера) →read;failedпісля 5 спроб, через 24 год або заretry: "no". - Офлайн-буфер: після обриву повідомлення йдуть у буфер (до 50 записів, 128 КіБ, 24 год): за згодою в
localStorage, без неї вsessionStorage, і надсилаються за наступногоinit_ok. - Кілька вкладок, одне з’єднання: вкладки сайту обирають ведучу (Web Locks, інакше сигнал підтримання в
localStorage); лише вона тримає з’єднання, інші спілкуються черезBroadcastChannel.
Резервний канал HTTP
Якщо мережа не пропускає WebSocket, чат працює через звичайні HTTPS-запити з тими самими кадрами й лімітами. Використовує лише віджет; інтерфейс операторів завжди підключається через WebSocket. Коротка версія для редакторів — Резервний канал HTTP.
Коли діє:
- браузер не підтримує WebSocket;
- дві спроби WebSocket поспіль невдалі до першого встановленого WebSocket на цій сторінці (спроба без результату за 8 секунд — невдала);
sessionStorageмістить записrc_http, якому менш як 30 хвилин (наступні сторінки тієї самої вкладки);- ви примусово задаєте
data-rc-transport="http"(на будь-якому елементі документа під час запуску) абоwindow.ReactiveChatSettings = { transport: 'http' }до завантажувача.ReactiveChat('boot', { transport: 'http' })не діє: тип з’єднання фіксується під час запуску.
Без fetch у браузері резервного каналу немає. Після обриву наявного WebSocket віджет підключається знову через WebSocket. Після переходу на резерв він тихо перевіряє раз на сторінку, чи вже проходить WebSocket; якщо так, видаляє rc_http, і наступна сторінка знову використовує WebSocket.
Запити (під https://ws.reactive.chat/rc_wss/h/):
- POST h/auf — відкриває з’єднання. Відповідь
{"v":1,"cid":"…","tok":"…","poll_ms":25000,"idle_ms":60000}.tok— короткочасний токен з’єднання (32 символи). - GET h/<cid>/sse?tok=… — Server-Sent Events,
id:іdata:на кадр, сигнал підтримання кожні 15 с. Пропущені кадри доставляються черезLast-Event-ID. - GET h/<cid>/poll?tok=…&nach=<n> — довге опитування; сервер тримає запит до 25 с і відповідає
{"v":1,"n":…,"rahmen":[…]}. - POST h/<cid>/tx?tok=… — надсилання,
text/plain, один кадр або масив до 20 кадрів; відповідь 204. - POST h/<cid>/zu?tok=… — закриття (через
sendBeacon).
Спочатку віджет пробує SSE; якщо перший кадр не надійшов за 5 секунд (наприклад через буферизацію проксі), переходить на довге опитування. Помилки 404 (unbekannt), 403, 413 або 429 обробляє як обрив із повтором після затримки. Після 60 секунд без запиту сервер закриває з’єднання. CORS: Access-Control-Allow-Origin віддзеркалює джерело без облікових даних; перевірка джерела відбувається в init, як із WebSocket.
Вимоги на вашому боці:
connect-srcвашої CSP містить адресу чату зwss://таhttps://.- Міжмережеві екрани й проксі дозволяють запити тривалістю щонайменше 30 секунд.
- Власний проксі передає
/rc_wss/без буферизації (nginxproxy_buffering offіproxy_cache off, Apacheflushpackets=on, Caddyflush_interval -1) та не записує/rc_wss/h/у журнал доступу (токен у запиті). Див. Власний домен.
Зберігається в браузері: лише запис rc_http у sessionStorage з часом HTTPS-з’єднання, без персональних даних.
Який шлях активний
На вкладці мережі інструментів розробника:
- WebSocket: з’єднання типу WebSocket з
wss://ws.reactive.chat/rc_wss/(або вашим піддоменом). У кадрах видноinit,init_ok,ping/pongі повідомлення. - Резервний канал HTTP: спочатку
h/auf, потім тривалий…/sse(або повторюваний…/poll) та один…/txна кожне надіслане повідомлення.
Далі: Ліміти й квоти · Усунення несправностей
Оновлено: