Gli utenti si aspettano un feedback immediato quando si verificano eventi: un nuovo messaggio di chat, un collega approva un documento, o un attivatore di avviso server. La costruzione di questa funzionalità in un'app web JavaScript richiede una pianificazione accurata, i protocolli di comunicazione giusti e il design di UI riflessivo. Questa guida ti guida attraverso l'implementazione di notifiche in tempo reale utilizzando WebSockets e Server-Sent Events (SSE), integrando loro sistemi di backend diretto.

Perché le notifiche in tempo reale

Le notifiche in tempo reale eliminano la necessità di aggiornare o inquinare la pagina manuale, che drena la larghezza di banda e degrada l'esperienza dell'utente. Quando un utente riceve un avviso immediato, rimangono impegnati e possono reagire prontamente. Per piattaforme SaaS, strumenti di collaborazione, o dashboard di e-commerce, questa immediatezza influisce direttamente sulla produttività e sulla soddisfazione.

Oltre all'esperienza degli utenti, le notifiche in tempo reale permettono anche di creare nuovi modelli di interazione: flussi di commenti dal vivo, cursori di editing collaborativi e feed di eventi lato server.

WebSocket: Comunicazione full-Duplex

WebSockets[[]] forniscono un canale bidirezionale persistente tra un client e un server. A differenza di HTTP, la connessione rimane aperta dopo la stretta di mano iniziale, permettendo a entrambi i lati di spingere i dati in qualsiasi momento. Questo rende WebSockets ideale per le applicazioni di chat, feed finanziari dal vivo e giochi multiplayer — qualsiasi scenario in cui la bassa latenza, la messaggistica a due vie è critica.

Creazione di una connessione WebSocket in JavaScript

L'API nativo del browser rende la configurazione della connessione semplice. Se istanzia un nuovo oggetto [ con l'URL del server (utilizzando il ] per connessioni sicure). Quindi allega gli ascoltatori degli eventi per , , e ]].

const socket = new WebSocket('wss://api.directus.app/websocket');

socket.onopen = () => {
 console.log('WebSocket connection established.');
 // Optionally send an authentication token
 socket.send(JSON.stringify({ type: 'auth', token: 'your-jwt' }));
};

socket.onmessage = (event) => {
 const data = JSON.parse(event.data);
 if (data.type === 'notification') {
 showToast(data.payload.message);
 }
};

socket.onerror = (err) => {
 console.error('WebSocket error:', err);
};

socket.onclose = (event) => {
 console.warn('WebSocket closed:', event.code, event.reason);
 // optional reconnect logic
};

Dopo aver stabilito la connessione, è possibile inviare messaggi e risposte di formato JSON nel gestore [. Il server deve supportare il protocollo WebSocket; molti framework Node.js (ad esempio, , []]) e backend CMS come Directus offrono il supporto WebSocket integrato o basato su-based.

Gestione della connessione e battiti cardiaci

Un sistema in tempo reale robusto deve gestire le interruzioni di rete con grazia.

function connectWebSocket() {
 const socket = new WebSocket('wss://api.directus.app/websocket');
 let retryDelay = 1000;

 socket.onclose = () => {
 setTimeout(() => {
 console.log('Reconnecting...');
 connectWebSocket();
 }, retryDelay);
 retryDelay = Math.min(retryDelay * 2, 30000);
 };

 // ...other handlers
}

connectWebSocket();

Inoltre, inviare pings battito cardiaco periodico (ogni 30–60 secondi) per rilevare connessioni stanti. Molte librerie WebSocket gestiscono questo automaticamente, ma se si sta utilizzando l'API grezzo, impostare un intervallo per inviare un messaggio e aspettarsi una risposta .

Eventi Server-Sent: Più semplice, streaming One-Way

Server-Sent Events (SSE)[]] sono un'alternativa leggera quando è necessario che il server spinga i dati ai client senza richiedere messaggi client-to-server. SSE utilizza HTTP standard; il server risponde con un intestazione e mantiene la connessione aperta. Il client legge il flusso tramite l'API .

SSE è più semplice da implementare rispetto a WebSockets, funziona su HTTP/2 e si ricollega automaticamente quando la connessione scende. Tuttavia, non supporta la comunicazione bidirezionale, quindi è più adatto per feed di notizie, ticker di magazzino, o avvisi di sistema.

Utilizzo di EventSource nel Browser

L'interfaccia del browser è minima:

const eventSource = new EventSource('/api/events?user_id=42');

eventSource.onopen = () => {
 console.log('SSE connection opened.');
};

eventSource.addEventListener('notification', (event) => {
 const data = JSON.parse(event.data);
 displayNotification(data);
});

eventSource.onerror = (err) => {
 console.error('EventSource error:', err);
 // The browser will automatically attempt to reconnect
};

function displayNotification(data) {
 // Update UI
}

Sul lato server, formatta ogni evento come linee di testo:

event: notification
data: {"message":"Your report is ready","severity":"info"}

Nota che l'API supporta solo le richieste GET e non può inviare intestazioni personalizzate. Se è necessario passare i token di autenticazione, applicarli come parametri di query (utilizzare HTTPS per evitare di esporre il token).

WebSocket vs. SSE: Scegliere l'approccio giusto

Entrambe le tecnologie sono in grado di gestire le notifiche in tempo reale, ma servono diversi casi di utilizzo:

Feature WebSocket SSE
Direction Bidirectional Server → Client only
Auto‑reconnect Must implement manually Built‑in
Binary data Yes (ArrayBuffer, Blob) Text only (UTF‑8)
Browser support Excellent (IE10+) Good (no IE/Edge Legacy)
Complexity Higher Lower

Se il client ha bisogno di inviare comandi o dati al server (ad esempio, marcando una notifica come lettura), WebSocket è la scelta naturale. Per i feed di notifica semplici, SSE riduce lo sviluppo in testa ed è più facile da debug perché utilizza intestazioni HTTP standard.

Integrazione di notifiche in tempo reale con Directus

Directus]] è un CMS senza testa che espone un API REST e GraphQL. Per aggiungere funzionalità in tempo reale, è possibile sfruttare il supporto WebSocket (introdotto in Directus 10.x) o impostare un endpoint SSE tramite un'estensione personalizzata.

WebSocket Abbonamento a Directus

L’endpoint WebSocket di Directus ([]) accetta i messaggi JSON per sottoscrivere, annullare l’iscrizione o autenticare. Ad esempio, ascoltare nuovi messaggi in una raccolta :

const ws = new WebSocket('wss://cms.example.com/websocket');

ws.onopen = () => {
 // Subscribe to changes on the notifications collection
 ws.send(JSON.stringify({
 type: 'subscribe',
 collection: 'notifications',
 query: { filter: { user_id: { _eq: currentUserId } } }
 }));
};

ws.onmessage = (event) => {
 const msg = JSON.parse(event.data);
 if (msg.type === 'subscription' && msg.event === 'create') {
 showNotification(msg.data);
 }
};

Questo approccio offloads la complessità della sincronizzazione in tempo reale al CMS, mentre l'app JavaScript deve gestire solo i dati in arrivo. Per l'autenticazione, inviare un token nel primo messaggio WebSocket (come mostrato in precedenza).

Visualizzazione delle notifiche nell'interfaccia utente

Una volta che avete i dati, l'esperienza dell'utente dipende da come lo presentate. Le notifiche di toast stilizzate sono il modello più comune: un piccolo, popup non invadente che appare all'angolo dello schermo e automaticamente-dismisses dopo pochi secondi.

In alternativa, costruire un componente di notifica personalizzato. Ecco un esempio minimo utilizzando JavaScript vaniglia e CSS:

function showToast(message, type = 'info') {
 const toast = document.createElement('div');
 toast.className = `toast toast-${type}`;
 toast.textContent = message;
 toast.setAttribute('role', 'alert');
 document.getElementById('toast-container').appendChild(toast);

 setTimeout(() => toast.remove(), 3000);
}

// CSS (simplified):
.toast {
 padding: 12px 20px;
 margin-bottom: 8px;
 border-radius: 4px;
 color: #fff;
 opacity: 0.9;
 transition: opacity 0.3s;
}
.toast-info { background: #007bff; }
.toast-error { background: #dc3545; }
.toast-success { background: #28a745; }

Assicurarsi che il contenitore sia fissato all'angolo in alto a destra e che i toast impilano verticalmente. Usa sul contenitore per garantire ai lettori di schermo di annunciare nuove notifiche.

Preferenze utente e Gestione delle notifiche

Non tutte le notifiche sono altrettanto importanti. Permettere agli utenti di personalizzare gli eventi che vogliono ricevere e attraverso i quali canali (in-app, e-mail, push). Conservare le preferenze nel backend e filtrare gli eventi sul server prima di spingerli al client. Ad esempio, un utente potrebbe disabilitare gli avvisi “nuovi commenti” ma mantenere gli avvisi “task assegnati”.

Nell'app JavaScript, fai periodicamente il profilo preferito dell'utente e regola i filtri di abbonamento di conseguenza. Se si utilizza Directus WebSockets, è possibile inviare una query di abbonamento aggiornata quando le preferenze cambiano.

Fallback per i browser non supportati

Mentre i browser moderni supportano in gran parte WebSockets e SSE, gli ambienti più vecchi (ad esempio, Internet Explorer 11 per WebSockets, IE/Edge Legacy per SSE) possono richiedere polifill o strategie di fallback.

  • Rileva il supporto[] con o .
  • Incandescenza[[[]]: Utilizzare un endpoint a lungo inquinante che restituisce nuovi eventi come JSON. Il cliente richiede l'endpoint ogni pochi secondi e elabora qualsiasi evento in sospeso.
  • Astrazione biblica[[]]: Usa una libreria come [] che rientra in modo trasparente da WebSocket a HTTP long-polling.

Quando si inquina, impostare un intervallo ragionevole (ad esempio, 5-10 secondi) e restituire una risposta vuota se non sono in sospeso eventi.

Considerazioni di sicurezza

Collegamenti in tempo reale introducono diversi vettori di sicurezza che devono essere affrontati:

  • Individuare ogni connessione[[]. Per WebSockets, inviare un JWT o un token di sessione nel primo messaggio. Per SSE, aggiungere un token come parametro di query (ma mai nell'URL se lo registri).
  • Validare e sanzionare tutti i dati[[] prima di spingerlo al client. Anche se il backend è affidabile, non emettere mai contenuti generati dall'utente raw in una notifica senza sfuggire.
  • Utilizzare protocolli sicuri[] ([, ]) per evitare attacchi di mezzo uomo.
  • Rate‐limit Connections[[] per utente di prevenire abusi. Directus espone le impostazioni di limitazione dei tassi che è possibile configurare.
  • Non esporre lo stato del server interno[[] attraverso i messaggi WebSocket o SSE.

Prestazioni e scalabilità

Poiché il numero di connessioni concorrenti cresce, il server deve gestirli in modo efficiente.

  • Utilizza un server WebSocket dedicato[[] (ad esempio, processo Node.js separato) e scala orizzontalmente con un bilanciatore di carico che supporta sessioni appiccicose WebSocket.
  • Broadcast solo agli utenti interessati[[[]]. Utilizzare camere o canali basati su ID utente, gruppo o filtro abbonamenti per evitare di inviare ogni evento ad ogni cliente.
  • Comprimere messaggi[[]]. Per i protocolli basati su testo, abilitare deflato per messaggio (WebSocket) o gzip (SSE su HTTP/2).
  • Sanime di connessione del motore[[[]] con metriche come connessioni aperte, velocità di trasmissione dei messaggi e tassi di errore.
  • Caching degli eventi server-sent[[]. Con SSE, è possibile sfruttare le intestazioni HTTP caching se il flusso è statico per un periodo (anche se le notifiche sono di solito dinamiche).

Mettere tutto insieme: un flusso di lavoro completo

Per illustrare un esempio di mondo reale, uniamo un backend Directus con un frontend JavaScript che utilizza SSE per le notifiche.

  1. Backend (Directus Extension): Creare un endpoint personalizzato a [[]] che controlla il token JWT dell'utente, quindi trasmette nuove notifiche da una coda (ad esempio, Redis pub/sub o un gancio Directus che scrive a una collection).
  2. Frontend:[] Al caricamento della pagina, autentica con Directus e apri un [] indicando ]. Ascoltare eventi.
  3. Visualizza:[] Ogni notifica ricevuta viene resa come un brindisi utilizzando un componente personalizzato, con opzioni per licenziare o aprire la risorsa relativa.
  4. Preferenze utente:[] Quando l'utente aggiorna le impostazioni di notifica tramite un modulo, invia un POST all'endpoint [ di Directus.

Questa architettura mantiene il cliente magra e spinge il sollevamento pesante a Directus e il suo sistema di gancio.

Testare le notifiche in tempo reale

Prima di distribuire, testare accuratamente la tua implementazione:

  • Prove di carico:[] Usare strumenti come [Artillery[] per simulare centinaia di connessioni WebSocket o SSE concorrenti. Misurare la latenza e la stabilità di connessione.
  • Troppo di rete:[] Usare Chrome DevTools per simulare lente 3G o condizioni offline. Verificare che la logica di riconnessione funziona e che non vengono fornite notifiche duplicate.
  • Cross-browser testing:[] Test in Firefox, Safari, Chrome e Edge. Per SSE, prova in Safari (che manca il supporto completo EventSource per eventi personalizzati – potrebbe essere necessario utilizzare un polifill).
  • Casi di bordo di sicurezza:[] Tenta di connettersi con i gettoni scaduti, o iniettare JSON malformato per garantire che i vostri gestori di errore non crash il client.

Conclusioni

Le notifiche in tempo reale non sono più un lusso; sono un'aspettativa di base nelle applicazioni web moderne. Levando WebSockets o SSE, combinato con un backend come Directus che fornisce ganci in tempo reale, è possibile fornire aggiornamenti istantanei senza schiacciare la vostra infrastruttura.

Iniziare piccolo: implementare un semplice brindisi per un tipo di evento, quindi gradualmente espandersi a più canali e preferenze dell'utente. La chiave è quella di iterare sull'esperienza dell'utente mantenendo il trasporto sottostante efficiente e manutenbile. Con gli approcci qui delineati, sarete ben sulla strada per una funzione in tempo reale di produzione-ready.