WebSocket em JavaScript: aplicações avançadas em tempo real

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: além do WebSocket básico

A compreensão básica de WebSocket permite criar um chat simples ou notificações. No entanto, para construir aplicações real-time de nível de produção — jogos multijogador, terminais financeiros, sistemas de edição colaborativa — é necessário dominar técnicas avançadas. Neste artigo, iremos além do "Hello, World" e abordaremos como criar aplicações WebSocket robustas, escaláveis e seguras em Node.js.

Vamos explorar quatro áreas principais: escalabilidade com Redis, gerenciamento de estados e salas, segurança e autorização, além de clusterização para funcionar em múltiplos processadores. Todos os exemplos de código são escritos em JavaScript usando a biblioteca ws e Node.js.



1. Escalabilidade com Pub/Sub (Redis)

Uma das principais limitações de um servidor WebSocket é que ele não pode "se comunicar" com outras instâncias. Se você tiver dois servidores rodando atrás de um balanceador de carga, um cliente conectado ao servidor A não receberá uma mensagem enviada pelo servidor B. A solução é usar o padrão Pub/Sub (publicador-assinante) baseado em Redis.

O Redis atua como um broker central: cada servidor se inscreve em um canal e publica mensagens nele. Dessa forma, uma mensagem enviada por qualquer servidor é instantaneamente distribuída para todos os outros.

const WebSocket = require('ws');const redis = require('redis');

const wss = new WebSocket.Server({ port: 8080 });const publisher = redis.createClient();const subscriber = redis.createClient();

// Inscrevendo-se no canal 'broadcast'subscriber.subscribe('broadcast');subscriber.on('message', (channel, message) => { // Envia a mensagem para todos os clientes conectados wss.clients.forEach(client => { if (client.readyState === WebSocket.OPEN) { client.send(message); } });});

wss.on('connection', (ws) => { ws.on('message', (data) => { // Publica a mensagem no Redis publisher.publish('broadcast', data.toString()); });});

Essa abordagem permite escalar horizontalmente sua aplicação praticamente sem limites. Ao adicionar um novo servidor, ele simplesmente cria sua própria inscrição no Redis.



2. Gerenciamento de salas e estados

Na maioria das aplicações real-time, é necessário agrupar clientes em "salas" (salas de chat, lobbies de jogos) e gerenciar seus estados. O básico wss.clients não oferece essa funcionalidade. Vamos implementar um sistema de salas simples, mas eficiente.

Criaremos um objeto rooms, onde a chave é o nome da sala e o valor é um Set de clientes WebSocket. Adicionaremos métodos para entrar, sair e transmitir dentro da sala.

const rooms = new Map();

function joinRoom(ws, roomName) { if (!rooms.has(roomName)) { rooms.set(roomName, new Set()); } rooms.get(roomName).add(ws); // Salva a sala no objeto ws para acesso rápido ws.room = roomName;}

function leaveRoom(ws) { if (ws.room && rooms.has(ws.room)) { rooms.get(ws.room).delete(ws); if (rooms.get(ws.room).size === 0) { rooms.delete(ws.room); } delete ws.room; }}

function broadcastToRoom(roomName, message, exclude = null) { if (!rooms.has(roomName)) return; rooms.get(roomName).forEach(client => { if (client !== exclude && client.readyState === WebSocket.OPEN) { client.send(message); } });}

const wss = new WebSocket.Server({ port: 8080 });wss.on('connection', (ws) => { ws.on('message', (data) => { const msg = JSON.parse(data); switch (msg.type) { case 'join': joinRoom(ws, msg.room); break; case 'message': broadcastToRoom(ws.room, msg.text, ws); break; } }); ws.on('close', () => leaveRoom(ws));});

Para gerenciar estados (por exemplo, posição do jogador, cursor), é possível armazenar dados em um Map

Blogs

Book Recommendations