Tutorial: Bouw een eenvoudige chatapp met een chathub

In deze tutorial bouw je een eenvoudige realtime chatflow met behulp van een Web PubSub chathub.

U:

  • Stel een backendserver in om clienttoegangs-URL's uit te geven
  • Verbind clients met een Web PubSub chathub
  • Een ruimte maken
  • Berichten verzenden en ontvangen
  • Kamerlidmaatschap beheren

Aan het einde heb je een werkende chatervaring ondersteund door Azure Web PubSub.

Prerequisites

  • Een Azure-abonnement
  • Node.js 18 of hoger

Maak een Web PubSub-bron met een chathub

Maak een Azure Web PubSub-resource aan en configureer een chathub genaamd demo-chat.

Afhankelijkheden installeren

Serverafhankelijkheden

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

Klantafhankelijkheden

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

Stap 1: Maak de backendserver aan

De backendserver is verantwoordelijk voor:

  • Gebruikers verifiëren
  • Het uitgeven van clienttoegangs-URL's

Servercode

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 }
);

Waarom deze stap bestaat

Hoewel de Web PubSub-service anonieme verbindingen ondersteunt, gebruikt het meest voorkomende productiepatroon een server-issued toegangsmodel.

Je server genereert een tijdsbeperkte clienttoegangs-URL die de gebruikersidentiteit en permissies codeert. Deze aanpak:

  • Houdt inloggegevens veilig
  • Stelt je app in staat om authenticatie en autorisatie te regelen
  • Sluit aan bij de beveiligingsverwachtingen van ondernemingen

Stap 2: Voeg een onderhandelingspunt toe

Het negotiate-endpoint geeft een clienttoegangs-URL terug die chatclients gebruiken om verbinding te maken.

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,
  });
});

Waarom deze stap bestaat

Chatclients moeten verbinding maken als een specifieke gebruiker.

Het negotiate-endpoint is waar je applicatie:

  • Koppelt een identiteit op appniveau aan een gebruiker in de chat
  • Genereert een tijdelijke URL voor toegang met beperkte reikwijdte
  • Bepaalt wie verbinding mag maken

In een productieomgeving doet dit endpoint doorgaans het volgende:

  • Controleert authenticatie (cookies, headers, tokens)
  • Handhaaft autorisatieregels

Stap 3: Start de server

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

Je backend is nu klaar om klantverbindingen te accepteren.

Stap 4: Verbind clients met de chathub

Haal op de client toegangs-URL's van de server op en log in op de demo-chat hub.

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}`);

Waarom deze stap bestaat

De Web PubSub chathub bouwt voort op het Web PubSub verbindingsmodel. Deze authenticatiestap:

  • Legt een realtime verbinding tot stand
  • Koppelt de verbinding aan een gebruikersidentiteit
  • Maakt chat-specifieke functies mogelijk zoals kamers en berichtgeschiedenis

Stap 5: Luister naar chat-evenementen

Registreer luisteraars om realtime updates te ontvangen.

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}`);
});

De chatclient is een event emitter. Naast message en room-joined, kun je luisteren naar room-left, member-joined, , member-left, started, en stopped. off Gebruik dezelfde argumenten om een luisteraar te verwijderen.

Waarom deze stap bestaat

Chat is van nature gebeurtenisgestuurd. Deze listeners stellen uw applicatie in staat om:

  • Reageer op binnenkomende berichten
  • Werk de gebruikersinterface bij wanneer gebruikers kamers binnenkomen
  • Blijf gesynchroniseerd over meerdere apparaten of browsertabbladen

Stap 6: Maak een kamer aan en stuur berichten

Maak een kamer aan en voeg eerste leden toe:

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

Stuur een bericht naar de kamer:

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

Berichten worden in realtime aan alle kamerleden overgebracht.

Waarom deze stap bestaat

Kamers bieden structuur voor gesprekken:

  • Zij bepalen wie berichten ontvangt.
  • Ze onderhouden de berichtgeschiedenis.
  • Ze maken het mogelijk om de chat verder te schalen dan één-op-één berichten.

Stap 7: Krijg berichtgeschiedenis

Haal eerdere berichten uit een kamer op. listRoomMessages Geeft een gepagineerde asynchrone iterator terug, zodat je direct over elk bericht kunt itereren:

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

Of laad de geschiedenis pagina voor pagina (bijvoorbeeld: "laad 50, dan 50 meer bij scroll-up"):

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

Waarom deze stap bestaat

Nieuw verbonden klanten hebben vaak context nodig.

Berichtgeschiedenis stelt je app in staat om:

  • Render bestaande berichten
  • Hervat de chat na het opnieuw verbinden
  • Ondersteuning voor gebruik van meerdere apparaten

Stap 8: Beheer ruimtedeelnemers

Voeg een gebruiker toe aan een kamer:

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

Verwijder een gebruiker uit een kamer:

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

Lidmaatschapswijzigingen gaan onmiddellijk in.

Stap 9: Opruimen

Wanneer de client geen berichten meer hoeft te ontvangen:

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

Wat u hebt gebouwd

In deze quickstart gaat u als volgt te werk:

  • Veilige clienttoegangs-URL's van een server uitgegeven
  • Clients verbonden met een chathub
  • Chatrooms aangemaakt en lid worden
  • Verzonden en ontvangen berichten in realtime
  • Geladen berichtgeschiedenis
  • Lidmaatschap van beheerde kamers

En dat alles zonder WebSocket-servers te beheren, fan-outlogica of berichtopslag.