Bilješka
Pristup ovoj stranici zahtijeva provjeru vjerodostojnosti. Možete pokušati da se prijavite ili promijenite direktorije.
Pristup ovoj stranici zahtijeva provjeru vjerodostojnosti. Možete pokušati promijeniti direktorije.
In this tutorial, you build a simple real-time chat flow using a Web PubSub chat hub.
You:
- Set up a backend server to issue client access URLs
- Connect clients to a Web PubSub chat hub
- Create a room
- Send and receive messages
- Manage room membership
By the end, you have a working chat experience backed by Azure Web PubSub.
Prerequisites
- An Azure subscription
- Node.js 18 or later
Create a Web PubSub resource with a chat hub
Create an Azure Web PubSub resource and configure a chat hub named demo-chat.
Install dependencies
Server dependencies
npm install express @azure/web-pubsub @azure/web-pubsub-express
Client dependencies
npm install @azure/web-pubsub-chat-client
Step 1: Create the backend server
The backend server is responsible for:
- Authenticating users
- Issuing client access URLs
Server code
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 }
);
Why this step exists
Although the Web PubSub service supports anonymous connections, the most common production pattern uses a server-issued access model.
Your server generates a time-limited client access URL that encodes the user identity and permissions. This approach:
- Keeps credentials secure
- Allows your app to control authentication and authorization
- Aligns with enterprise security expectations
Step 2: Add a negotiate endpoint
The negotiate endpoint returns a client access URL that chat clients use to connect.
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,
});
});
Why this step exists
Chat clients must connect as a specific user.
The negotiate endpoint is where your application:
- Maps app-level identity to a chat user
- Issues a scoped, temporary access URL
- Decides who is allowed to connect
In production, this endpoint typically:
- Verifies authentication (cookies, headers, tokens)
- Enforces authorization rules
Step 3: Start the server
app.listen(port, () => {
console.log(`Server listening at http://localhost:${port}`);
});
Your backend is now ready to accept client connections.
Step 4: Connect clients to the chat hub
On the client, fetch access URLs from the server and log in to the 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}`);
Why this step exists
The Web PubSub chat hub builds on the Web PubSub connection model. This authentication step:
- Establishes a real-time connection
- Associates the connection with a user identity
- Enables chat-specific features such as rooms and message history
Step 5: Listen for chat events
Register listeners to receive real-time updates.
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}`);
});
The chat client is an event emitter. In addition to message and room-joined, you can listen for room-left, member-joined, member-left, started, and stopped. Use off with the same arguments to remove a listener.
Why this step exists
Chat is inherently event-driven. These listeners allow your application to:
- React to incoming messages
- Update the UI when users join rooms
- Stay synchronized across multiple devices or browser tabs
Step 6: Create a room and send messages
Create a room and add initial members:
const room = await alice.createRoom('My Room', ['charlie']);
Send a message to the room:
await alice.sendToRoom(room.roomId, 'Hello!');
Messages are delivered in real time to all room members.
Why this step exists
Rooms provide structure for chat:
- They define who receives messages.
- They maintain message history.
- They allow chat to scale beyond one-to-one messaging.
Step 7: Get message history
Retrieve previous messages from a room. listRoomMessages returns a paged async iterator, so you can iterate over every message directly:
for await (const msg of alice.listRoomMessages(room.roomId)) {
console.log(`${msg.createdBy}: ${msg.content.text}`);
}
Or load history one page at a time (for example, "load 50, then 50 more on scroll-up"):
const pages = alice.listRoomMessages(room.roomId).byPage({ maxPageSize: 50 });
const firstPage = await pages.next();
const messages = firstPage.value ?? [];
Why this step exists
Newly connected clients often need context.
Message history allows your app to:
- Render existing messages
- Resume chat after reconnects
- Support multi-device usage
Step 8: Manage room members
Add a user to a room:
await alice.addUserToRoom(room.roomId, 'bob');
Remove a user from a room:
await alice.removeUserFromRoom(room.roomId, 'bob');
Membership changes take effect immediately.
Step 9: Clean up
When the client no longer needs to receive messages:
await alice.stop();
await charlie.stop();
What you built
In this quickstart, you:
- Issued secure client access URLs from a server
- Connected clients to a chat hub
- Created and joined chat rooms
- Sent and received messages in real time
- Loaded message history
- Managed room membership
All without managing WebSocket servers, fan-out logic, or message persistence.