Tutorial: Crea una semplice app di chat con un chat hub

In questo tutorial, costruisci un semplice flusso di chat in tempo reale usando un hub di chat Web PubSub.

Tu:

  • Configura un server backend per emettere URL di accesso ai client
  • Collega i client a un hub di chat Web PubSub
  • Creare una sala
  • Inviare e ricevere messaggi
  • Gestire l'appartenenza alla stanza

Alla fine, hai un'esperienza di chat lavorativa supportata da Azure Web PubSub.

Prerequisiti

  • Una sottoscrizione di Azure
  • Node.js versione 18 o successive

Crea una risorsa Web PubSub con un chat hub

Crea una risorsa Azure Web PubSub e configura un chat hub chiamato demo-chat.

Installa le dipendenze

Dipendenze del server

npm install express @azure/web-pubsub @azure/web-pubsub-express

Dipendenze dei clienti

npm install @azure/web-pubsub-chat-client

Passo 1: Crea il server backend

Il server backend è responsabile di:

  • Autenticazione degli utenti
  • Emissione di URL di accesso ai client

Codice server

import express from 'express';
import { WebPubSubServiceClient } from '@azure/web-pubsub';
import { WebPubSubEventHandler } from '@azure/web-pubsub-express';

const hubName = 'demo-chat';
const port = process.env.PORT || 3000;

const connectionString = process.env.WEB_PUBSUB_CONNECTION_STRING;
if (!connectionString) {
  throw new Error('WEB_PUBSUB_CONNECTION_STRING is not set');
}

const app = express();

const serviceClient = new WebPubSubServiceClient(
  connectionString,
  hubName,
  { allowInsecureConnection: true }
);

Perché esiste questo passaggio

Sebbene il servizio Web PubSub supporti connessioni anonime, il modello di produzione più comune utilizza un modello di accesso fornito dal server.

Il tuo server genera un URL di accesso client a tempo limitato che codifica l'identità utente e i permessi. Questo approccio:

  • Mantiene le credenziali sicure
  • Permette alla tua app di controllare l'autenticazione e l'autorizzazione
  • In linea con le aspettative di sicurezza aziendale

Passo 2: Aggiungi un endpoint di negoziazione

L'endpoint negoziato restituisce un URL di accesso al client che i client di chat usano per connettersi.

app.get('/negotiate', async (req, res) => {
  console.log(`received negotiate request: ${JSON.stringify(req.query)}`);

  const userId = req.query.userId;
  if (!userId) {
    return res.status(400).send('Missing userId');
  }

  const token = await serviceClient.getClientAccessToken({
    userId,
  });

  res.json({
    url: token.url,
  });
});

Perché esiste questo passaggio

I client di chat devono connettersi come un utente specifico.

L'endpoint di negoziazione è dove risiede l'applicazione:

  • Mappare l'identità a livello di app a un utente della chat
  • Genera un URL di accesso temporaneo a ambito limitato
  • Decide chi può connettersi

In produzione, questo endpoint in genere:

  • Verifica l'autenticazione (cookie, header, token)
  • Applica le regole di autorizzazione

Passo 3: Avvia il server

app.listen(port, () => {
  console.log(`Server listening at http://localhost:${port}`);
});

Il tuo backend è ora pronto ad accettare le connessioni dei clienti.

Passo 4: Collega i client all'hub di chat

Sul client, prendi gli URL di accesso dal server e accedi all'hub demo-chat .

import { ChatClient } from '@azure/web-pubsub-chat-client';

// Fetch a fresh client access URL from the negotiate endpoint.
const getClientAccessUrl = (userId) =>
  fetch(`/negotiate?userId=${userId}`)
    .then(r => r.json())
    .then(d => d.url);

// Option 1: start with a one-time client access URL.
const alice = await ChatClient.start(await getClientAccessUrl('alice'));
console.log(`Started as: ${alice.userId}`);

// Option 2: start with a credential so the client can refresh the URL itself.
const charlie = await ChatClient.start({
  getClientAccessUrl: () => getClientAccessUrl('charlie'),
});
console.log(`Started as: ${charlie.userId}`);

Perché esiste questo passaggio

Il chat hub Web PubSub si basa sul modello di connessione Web PubSub. Questo passaggio di autenticazione:

  • Stabilisce una connessione in tempo reale
  • Associa la connessione a un'identità utente
  • Abilita funzionalità specifiche per la chat come stanze e cronologia dei messaggi

Passo 5: Ascolta gli eventi di chat

Registra gli ascoltatori per ricevere aggiornamenti in tempo reale.

alice.on('message', (event) => {
  const msg = event.message;
  console.log(`Alice received: ${msg.createdBy}: ${msg.content.text}`);
});

alice.on('room-joined', (event) => {
  console.log(`Alice joined room: ${event.room.title}`);
});

charlie.on('message', (event) => {
  const msg = event.message;
  console.log(`Charlie received: ${msg.createdBy}: ${msg.content.text}`);
});

charlie.on('room-joined', (event) => {
  console.log(`Charlie joined room: ${event.room.title}`);
});

Il client di chat è un emettitore di eventi. Oltre a message e room-joined, puoi ascoltare room-left, member-joined, member-left, started e stopped. Usa off con gli stessi argomenti per rimuovere un ascoltatore.

Perché esiste questo passaggio

La chat è intrinsecamente guidata dagli eventi. Questi listener consentono alla tua applicazione di:

  • Reagire ai messaggi in arrivo
  • Aggiorna l'interfaccia utente quando gli utenti entrano nelle stanze
  • Rimani sincronizzato su più dispositivi o schede del browser

Passo 6: Crea una stanza e invia messaggi

Crea una stanza e aggiungi i membri iniziali:

const room = await alice.createRoom('My Room', ['charlie']);

Invia un messaggio alla stanza:

await alice.sendToRoom(room.roomId, 'Hello!');

I messaggi vengono consegnati in tempo reale a tutti i membri della sala.

Perché esiste questo passaggio

Le stanze offrono una struttura per la chat:

  • Definiscono chi riceve i messaggi.
  • Mantengono la cronologia dei messaggi.
  • Permettono alla chat di espandere oltre la messaggistica uno a uno.

Passo 7: Ottieni la cronologia dei messaggi

Recupera i messaggi precedenti da una stanza. listRoomMessages restituisce un iteratore asincrono paginato, quindi puoi iterare direttamente su tutti i messaggi:

for await (const msg of alice.listRoomMessages(room.roomId)) {
  console.log(`${msg.createdBy}: ${msg.content.text}`);
}

Oppure carica la cronologia una pagina alla volta (ad esempio, "carica 50, poi altre 50 scorriendo verso l'alto"):

const pages = alice.listRoomMessages(room.roomId).byPage({ maxPageSize: 50 });
const firstPage = await pages.next();
const messages = firstPage.value ?? [];

Perché esiste questo passaggio

I client appena collegati spesso hanno bisogno di contesto.

La cronologia dei messaggi permette alla tua app di:

  • Visualizzare i messaggi esistenti
  • Riprendi la chat dopo la riconnessione
  • Supporta l'uso multidispositivo

Passo 8: Gestire i membri della stanza

Aggiungi un utente a una stanza:

await alice.addUserToRoom(room.roomId, 'bob');

Rimuovere un utente da una stanza:

await alice.removeUserFromRoom(room.roomId, 'bob');

Le modifiche ai membri entrano in vigore immediatamente.

Passo 9: Pulire

Quando il client non ha più bisogno di ricevere messaggi:

await alice.stop();
await charlie.stop();

Ciò che hai creato

Questo avvio rapido spiega come:

  • URL di accesso sicuro al client rilasciati da un server
  • Hanno collegato i client a un hub di chat
  • Chat room create e a cui si è partecipato
  • Messaggi inviati e ricevuti in tempo reale
  • Cronologia dei messaggi caricati
  • Appartenenza a stanze gestite

Tutto senza gestire server WebSocket, logica di fan-out o persistenza dei messaggi.