Trasporto: WebSocket, fallback HTTP e riconnessione
Come il widget comunica con il server della chat: indirizzi, sottoprotocollo rc.v1, formato delle trame, codici di errore e chiusura, limiti, riconnessione con seq e deduplicazione e fallback HTTP tramite Server-Sent Events e long polling.
Questa pagina descrive ciò che avviene tra il widget nel browser e il server della chat. Serve per la risoluzione dei problemi (scheda Rete degli strumenti per sviluppatori), per le regole di proxy e firewall e per la Sua Content Security Policy.
Importante: il protocollo di comunicazione è l’interfaccia tra il nostro widget e il nostro server. I client personalizzati che usano direttamente il protocollo non sono ufficialmente supportati; i campi possono essere estesi nella versione 1 del protocollo. Per le Sue interfacce usi l’API JavaScript, per i collegamenti server i webhook e l’API server.
Indirizzi
- WebSocket:
wss://ws.reactive.chat/rc_wss/ - Fallback HTTP, modulo offline, caricamenti: lo stesso indirizzo con
https://, cioèhttps://ws.reactive.chat/rc_wss/h/…,https://ws.reactive.chat/api/offline/<SITE_KEY>ehttps://ws.reactive.chat/rc_wss/upload/… - File del widget:
https://cdn.reactive.chat/
Come il widget trova l’indirizzo WebSocket:
data-rc-ws-urlsul tag del caricatore,window.ReactiveChatSettings.wsUrloReactiveChat('boot', { wsUrl }): se impostato, si applica questo valore.- Altrimenti viene ricavato dalla posizione di
loader.js:wss://ws.+ le ultime due componenti del dominio +/rc_wss/.cdn.reactive.chatdiventawss://ws.reactive.chat/rc_wss/.
Ne derivano due insidie:
- Se distribuisce
loader.jsdal Suo dominio, il widget ricava un indirizzo sotto il Suo dominio. In questo caso impostidata-rc-ws-url(veda Avvio rapido). - Con suffissi composti come
.co.uk, il calcolo è errato. Imposti esplicitamentedata-rc-ws-url.
Il percorso WebSocket non valuta i parametri della query.
Stabilire la connessione
- Quando: il widget non si connette durante il caricamento della pagina, ma alla prima interazione reale (movimento del mouse, clic, pressione di un tasto, rotella, tocco, focus). Si connette subito se la finestra della chat è aperta o viene aperta, se è nota una conversazione del visitatore o se ci sono messaggi non inviati in attesa. Con
data-rc-connect="load"su qualsiasi elemento (di solito il tag del caricatore) owindow.ReactiveChatSettings.connect = 'load'si connette al caricamento come prima. Le regole che scattano dopo un certo tempo dalla visualizzazione della pagina contano dalla prima interazione. - Sottoprotocollo: il widget apre
new WebSocket(url, 'rc.v1')e il server restituiscerc.v1. La versione del protocollo non è nell’indirizzo, ma in ogni trama (v: 1). - Solo trame di testo, in UTF-8; una trama = un messaggio. Nessuna compressione (
permessage-deflateè disattivato lato server). - Handshake: dopo
openil widget inviainitentro 5 secondi; il server risponde coninit_ok. Seopennon arriva entro 8 secondi, il tentativo è considerato fallito; seinit_oknon arriva entro 10 secondi, il widget si riconnette. - Verifica dell’origine: il server confronta il nome host dell’header
Origincon i domini del progetto (Origini consentite nell’account). Schema e porta non contano; i sottodomini corrispondono (www.your-company.comcorrisponde ayour-company.com,notyour-company.comno). In caso di errore:origin_denied, poi chiusura 1008, nessun nuovo tentativo. Se nel progetto non è inserito alcun dominio, non viene eseguita la verifica dell’origine: inserisca quindi sempre i Suoi domini.
Formato delle trame
Ogni messaggio in entrambe le direzioni ha questa forma:
{ "v": 1, "t": "msg", "id": "01JAB3C4D5E6F7G8H9JKMNPQRS", "ts": 1792500000000, "d": { } }
- v (intero, obbligatorio) – versione del protocollo, attualmente
1. - t (stringa, obbligatorio) – tipo di messaggio,
[a-z0-9_]{1,24}. - id (stringa, obbligatorio) – ULID: 26 caratteri Crockford Base32, solo maiuscoli. È anche la chiave per la deduplicazione.
- ts (intero, obbligatorio) – millisecondi dal 1970, solo per la diagnostica.
- d (oggetto, obbligatorio) – dati trasmessi, mai
null,{}se vuoto.
Tipi e campi sconosciuti vengono ignorati senza avviso: questo mantiene la compatibilità dei widget meno recenti con i server più recenti.
Tipi di messaggio a colpo d’occhio
Dal widget al server:
- init – registrazione della connessione: chiave del sito, ID di sessione, visitatore, scheda e conversazione, lingua, stato del consenso, eventuale identità firmata (
user), contesto della pagina (ctx) e punto di ripresa (resume). - msg – messaggio del visitatore (testo, fino a 5 allegati, risposta a risposte rapide o moduli).
- typing – indicatore di digitazione (
start/stop). Il contenuto del campo di input non viene mai trasmesso. - read – letto fino a
seq. - ctx – cambiamento del contesto, ad esempio durante la navigazione in una SPA o dopo
identify. - csat – valutazione (pollice su/giù, commento fino a 1000 caratteri).
- upload_req – richiesta di autorizzazione al caricamento (nome, tipo MIME, dimensione, SHA-256).
- transcript, forget, consent – conversazione via e-mail, eliminazione dei propri dati, concessione/revoca del consenso.
- ping – mantenimento della connessione.
Dal server al widget:
- init_ok – ID confermati, cronologia, aspetto, funzioni e limiti (veda sotto), risultato della verifica dell’identità (
identity.verified). - msg – messaggi (compresa la copia del messaggio del visitatore con
client_id). - bot_typing, bot_stream – l’assistente IA sta pensando o scrivendo;
bot_streamtrasmette sempre l’intero testo visibile fino a quel momento, al massimo ogni 150 ms. - typing, read, handoff, queue_pos, proactive, conv_list, error, pong.
Codici di errore
Un errore arriva come trama t: "error" con d.code, d.message (inglese, solo per sviluppatori), d.retry (no, immediate, backoff, after_reinit) e, se necessario, d.retry_after_ms e d.detail. L’elenco è chiuso; un codice sconosciuto viene trattato come internal.
- bad_json – JSON non valido; dopo tre occorrenze, chiusura 1008.
- bad_envelope – la trama viola il formato (anche: ULID con scarto superiore a 24 h,
detail.reason: stale_or_future). - unsupported_version – impossibile negoziare la versione; chiusura 4001.
- unknown_site_key – chiave del sito sconosciuta, progetto in pausa o archiviato; chiusura 4002.
- origin_denied – origine non compresa nei domini del progetto; chiusura 1008.
- visitor_blocked – visitatore bloccato; chiusura 1008.
- auth_failed – verifica dell’identità fallita,
detail.reason:no_hash,bad_hash,bad_exp,expired,exp_too_far. La sessione continua in forma anonima. - not_initialized / already_initialized – messaggio prima di
inito un secondoinit. - init_timeout – nessun
initentro 5 s; chiusura 4004. - conversation_not_found / conversation_closed
- rate_limited – limite di frequenza; con
retry_after_ms. Se accade ripetutamente sulla stessa connessione, il server chiude con 4008. - payload_too_large – trama oltre 64 KiB.
- msg_too_long – testo più lungo del limite del piano,
detail.max. - unsupported_kind, attachment_invalid
- upload_disabled, upload_too_large, upload_mime_denied, upload_expired
- consent_required – l’azione richiede il consenso.
- dnd_active – «Non disturbare» è attivo.
- session_conflict – troppe connessioni della stessa sessione (oltre 3); chiusura 4003, la scheda diventa una scheda secondaria.
- internal, unavailable – temporaneo; nuovo tentativo dopo un’attesa.
Codici di chiusura
- 1000, 1001, 1006, 1011, 1013, 4004 – il widget si riconnette (dopo un’attesa).
- 1008 – origine rifiutata, JSON ripetutamente non valido, blocco della protezione dagli abusi. Nessun nuovo tentativo su questa pagina.
- 4001 – impossibile negoziare la versione. Nessun nuovo tentativo.
- 4002 – chiave del sito sconosciuta o progetto inattivo. Nessun nuovo tentativo.
- 4008 – limitazione di frequenza ripetuta. Il widget attende
retry_after_mse si riconnette. - 4003 – conflitto di sessione; la scheda funziona come secondaria di un’altra scheda.
Limiti per connessione
Il server invia i valori vincolanti in init_ok.limits e init_ok.features:
- heartbeat_ms 25.000 – il widget invia un
ping25 s dopo l’ultimo messaggio in uscita. - pong_timeout_ms 10.000 – due
pongmancanti portano a una riconnessione. - idle_timeout_ms 70.000 – il server chiude dopo 70 s senza una trama in ingresso (1001).
- max_frame_bytes 65.536 – trame più grandi:
payload_too_large. - msg_per_10s 20 e frames_per_10s 120 – token bucket per connessione; oltre,
rate_limited. - reconnect_cap_ms 30.000 – attesa massima tra i tentativi.
- dedup_window_ms 86.400.000 – 24 ore di deduplicazione.
- features.max_msg_len – caratteri (punti di codice Unicode) per messaggio del visitatore: 1000 nel piano Free, 4000 nei piani a pagamento. Il widget non invia testi troppo lunghi.
- features.max_upload_bytes, features.allowed_mime – veda Limiti e quote.
Riconnessione, ordine, duplicati
- Attesa:
min(30000, 500 × 2^(attempt−1))ms, di cui viene usato un valore casuale nella metà superiore (tentativo 1: 250–500 ms, dal tentativo 7: 15–30 s). Tre volte più lunga nelle schede in background. Unretry_after_msdel server è il limite inferiore. Il numero di tentativi è illimitato; il contatore si azzera solo coninit_ok. Se il browser segnalaonline, il widget riprova subito; se è offline, attende. - Ordine: ogni messaggio di una conversazione ha un
seqsenza interruzioni a partire da 1. I messaggi vengono visualizzati secondoseq, non secondo l’ora. Alla riconnessione, il widget inviaresume.last_seqe fino a 50 ID in attesa; il server consegna tutto ciò che segue (massimo 100 messaggi, altrimentihas_more) e ripete le conferme dei messaggi già arrivati. - Nessun duplicato: il server ricorda ogni
iddi messaggio per 24 ore. Un messaggio ripetuto non viene memorizzato di nuovo, ma riceve la stessa conferma. «Invia di nuovo» nel widget usa lo stessoid. - Stati di un messaggio in uscita:
pending→sent→delivered(copia dal server) →read;faileddopo 5 tentativi, dopo 24 h o conretry: "no". - Buffer offline: se la connessione cade, i messaggi finiscono in un buffer (massimo 50 voci, 128 KiB, 24 h), con consenso in
localStorage, senza insessionStorage, e vengono inviati al successivoinit_ok. - Più schede, una connessione: le schede di un sito web eleggono una principale (Web Locks, altrimenti mantenimento della connessione in
localStorage); solo la principale mantiene la connessione e le altre comunicano tramiteBroadcastChannel.
Fallback HTTP
Se una rete non lascia passare un WebSocket, la chat prosegue tramite normali richieste HTTPS, con le stesse trame e gli stessi limiti. Lo usa solo il widget; l’interfaccia operatori si connette sempre via WebSocket. La versione breve per i redattori si trova in Fallback HTTP.
Quando si applica:
- il browser non supporta WebSocket;
- due tentativi WebSocket falliscono consecutivamente prima che sia mai stata stabilita una connessione WebSocket su questa pagina (un tentativo senza risultato dopo 8 secondi conta come fallito);
sessionStoragecontiene una vocerc_httprisalente a meno di 30 minuti prima (pagine successive nella stessa scheda);- lo impone con
data-rc-transport="http"(su qualsiasi elemento presente nel documento all’avvio) o conwindow.ReactiveChatSettings = { transport: 'http' }prima del caricatore.ReactiveChat('boot', { transport: 'http' })non ha effetto: il tipo di connessione viene fissato all’avvio.
Senza fetch nel browser non c’è fallback. Se una connessione WebSocket esistente cade, il widget si riconnette via WebSocket. Dopo un fallback, verifica senza avvisi una volta per pagina se un WebSocket riesce ora a passare; in caso positivo elimina rc_http e la pagina successiva usa di nuovo WebSocket.
Le richieste (sotto https://ws.reactive.chat/rc_wss/h/):
- POST h/auf – apre la connessione. Risposta
{"v":1,"cid":"…","tok":"…","poll_ms":25000,"idle_ms":60000}.tokè un token di connessione di breve durata (32 caratteri). - GET h/<cid>/sse?tok=… – Server-Sent Events,
id:edata:per trama, mantenimento della connessione ogni 15 s. Le trame perse vengono consegnate tramiteLast-Event-ID. - GET h/<cid>/poll?tok=…&nach=<n> – long polling; il server mantiene aperta la richiesta fino a 25 s e risponde con
{"v":1,"n":…,"rahmen":[…]}. - POST h/<cid>/tx?tok=… – invio,
text/plain, una trama o un array di massimo 20 trame; risposta 204. - POST h/<cid>/zu?tok=… – chiusura (tramite
sendBeacon).
Il widget prova prima SSE; se non arriva una prima trama entro 5 secondi (ad esempio perché un proxy usa buffering), passa al long polling. Tratta errori come 404 (unbekannt), 403, 413 o 429 come una connessione interrotta e riprova dopo un’attesa. Dopo 60 secondi senza richieste, il server chiude la connessione. CORS: Access-Control-Allow-Origin rispecchia l’origine, senza credenziali; la verifica dell’origine avviene in init, come per WebSocket.
Requisiti dal Suo lato:
connect-srcdella Sua CSP contiene l’indirizzo della chat conwss://ehttps://.- Firewall e proxy consentono richieste della durata di almeno 30 secondi.
- Il Suo proxy inoltra
/rc_wss/senza buffering (nginxproxy_buffering offeproxy_cache off, Apacheflushpackets=on, Caddyflush_interval -1) e non scrive/rc_wss/h/nel registro degli accessi (token nella query). Veda Dominio personalizzato.
Memorizzato nel browser: solo la voce rc_http in sessionStorage con l’ora della connessione HTTPS, senza dati personali.
Quale percorso è attivo
Nella scheda Rete degli strumenti per sviluppatori:
- WebSocket: una connessione di tipo WebSocket a
wss://ws.reactive.chat/rc_wss/(o al Suo sottodominio). Nelle trame vedeinit,init_ok,ping/ponge i messaggi. - Fallback HTTP: prima
h/auf, poi una richiesta di lunga durata…/sse(o richieste ricorrenti…/poll) e una…/txper ogni messaggio inviato.
Prosegua: Limiti e quote · Risoluzione dei problemi
Última actualización: