Handledning: Bygg en enkel chattapp med en chatthubb

I denna handledning bygger du ett enkelt chattflöde i realtid med hjälp av en Web PubSub-chatthubb.

Du:

  • Sätt upp en backend-server för att utfärda klientåtkomst-URL:er
  • Koppla klienter till en Web PubSub-chatthubb
  • Skapa ett rum
  • Skicka och ta emot meddelanden
  • Hantera rumsmedlemskap

I slutet har du en fungerande chattupplevelse som backas upp av Azure Web PubSub.

Förutsättningar

  • En prenumeration på Azure
  • Node.js 18 eller senare

Skapa en Web PubSub-resurs med en chatthubb

Skapa en Azure Web PubSub-resurs och konfigurera en chatthubb som heter demo-chat.

Installera beroenden

Serverberoenden

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

Klientberoenden

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

Steg 1: Skapa backend-servern

Backend-servern ansvarar för:

  • Autentisera användare
  • Utfärdar klientåtkomst-URL:er

Serverkod

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

Varför detta steg finns

Även om Web PubSub-tjänsten stödjer anonyma anslutningar använder det vanligaste produktionsmönstret en serverutfärdad åtkomstmodell.

Din server genererar en tidsbegränsad klientåtkomst-URL som kodar användaridentiteten och behörigheterna. Den här metoden:

  • Håller inloggningsuppgifterna säkra
  • Låter din app styra autentisering och auktorisation
  • Stämmer överens med företags säkerhetsförväntningar

Steg 2: Lägg till en förhandlingsslutpunkt

Förhandla-endpointen returnerar en klientåtkomst-URL som chattklienter använder för att ansluta sig.

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

Varför detta steg finns

Chattklienter måste ansluta som en specifik användare.

Förhandlingsändpunkten är där din applikation:

  • Kopplar identitet på appnivå till en användare i chatten
  • Utfärdar en URL för tillfällig, avgränsad åtkomst
  • Bestämmer vem som får ansluta

I produktion brukar denna ändpunkt typiskt:

  • Verifierar autentisering (cookies, headers, tokens)
  • Upprätthåller auktorisationsregler

Steg 3: Starta servern

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

Din backend är nu redo att ta emot klientanslutningar.

Steg 4: Koppla klienter till chatthubben

På klienten, hämta åtkomst-URL:er från servern och logga in på demo-chat hubben.

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

Varför detta steg finns

Web PubSub chatthubb bygger vidare på Web PubSub-anslutningsmodellen. Detta autentiseringssteg:

  • Etablerar en realtidsanslutning
  • Kopplar anslutningen till en användaridentitet
  • Möjliggör chattspecifika funktioner som rum och meddelandehistorik

Steg 5: Lyssna efter chatthändelser

Registrera lyssnare för att få uppdateringar i realtid.

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

Chattklienten är en händelseutsändare. Utöver message och room-joinedkan du lyssna efter room-left, member-joined, , member-left, started, och stopped. off Använd samma argument för att ta bort en lyssnare.

Varför detta steg finns

Chatten är i grunden händelsestyrd. Dessa lyssnare gör det möjligt för din ansökan att:

  • Reagera på inkommande meddelanden
  • Uppdatera gränssnittet när användare går med i rum
  • Håll synkroniseringen över flera enheter eller webbläsarflikar

Steg 6: Skapa ett rum och skicka meddelanden

Skapa ett rum och lägg till initiala medlemmar:

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

Skicka ett meddelande till rummet:

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

Meddelanden levereras i realtid till alla rumsmedlemmar.

Varför detta steg finns

Rum ger struktur för chatt:

  • De definierar vem som tar emot meddelanden.
  • De upprätthåller meddelandehistorik.
  • De gör att chatten kan skalas bortom en-till-en-meddelanden.

Steg 7: Få meddelandehistorik

Hämta tidigare meddelanden från ett rum. listRoomMessages returnerar en sidindelad asynkron iterator, så att du kan iterera igenom varje meddelande direkt:

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

Eller ladda historik en sida i taget (till exempel "ladda 50, sedan 50 till vid scrollning upp"):

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

Varför detta steg finns

Nyanslutna klienter behöver ofta kontext.

Meddelandehistorik tillåter din app att:

  • Rendera befintliga meddelanden
  • Återuppta chatten efter återanslutning
  • Stöd för användning av flera enheter

Steg 8: Hantera rumsmedlemmar

Lägg till en användare i ett rum:

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

Ta bort en användare från ett rum:

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

Medlemsändringar träder i kraft omedelbart.

Steg 9: Städa upp

När klienten inte längre behöver ta emot meddelanden:

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

Det du har skapat

I den här snabbstarten kommer du att göra följande:

  • Utfärdade säkra klientåtkomst-URL:er från en server
  • Anslutna klienter till en chatthubb
  • Skapade och gick med i chattrum
  • Skickade och mottog meddelanden i realtid
  • Laddad meddelandehistorik
  • Medlemskap i hanterat rum

Allt detta utan att hantera WebSocket-servrar, fan-out-logik eller meddelandepersistens.