WebSockets na Prática: Sistema de Notificações em Tempo Real com Node.js e React
O problema que polling não resolve
Uma requisição HTTP a cada 5 segundos para checar notificações novas. Multiplique por 10 mil usuários conectados. São 2 mil requests por segundo no seu servidor, e a maioria retorna 304 ou um array vazio. O polling funciona, mas o custo é desproporcional ao valor entregue.
WebSocket resolve isso invertendo a direção: o servidor empurra dados para o cliente quando há algo novo. Uma conexão TCP persistente, bidirecional, com overhead de framing mínimo (2 a 14 bytes por mensagem, contra centenas de bytes de headers HTTP por request de polling).
Este post implementa um sistema de notificações completo: servidor WebSocket com autenticação no handshake, broadcast por canal de usuário, reconexão automática no React e tratamento dos erros que aparecem quando a conexão cai no meio de uma mensagem.
Escolhendo a biblioteca: ws vs Socket.IO vs uWebSockets.js
Antes de escrever código, a decisão de biblioteca importa. Cada uma carrega trade-offs reais.
| Critério | ws | Socket.IO | uWebSockets.js |
|---|---|---|---|
| Protocolo | WebSocket puro (RFC 6455) | Protocolo próprio sobre WebSocket/polling | WebSocket puro |
| Overhead de payload | Nenhum | ~50-100 bytes por mensagem (envelope de evento) | Nenhum |
| Fallback HTTP long-polling | Não | Sim, automático | Não |
| Reconexão automática (client) | Manual | Embutida | Manual |
| Performance (mensagens/s em single thread) | ~40k | ~15k | ~100k+ |
| Compatibilidade com proxy/CDN | Alta (padrão RFC) | Média (precisa configurar sticky sessions) | Alta |
| Tamanho do pacote (client) | ~2 KB | ~45 KB (minificado) | N/A (sem client oficial) |
Para notificações, onde o payload é pequeno e o servidor envia mais do que recebe, ws é a escolha direta. Socket.IO adiciona complexidade (rooms, namespaces, protocolo próprio) que não justifica o overhead quando você não precisa de fallback para navegadores antigos. uWebSockets.js entrega performance superior, mas a API é menos ergonômica e a manutenção do projeto é irregular.
Este post usa ws no backend e a API nativa WebSocket do navegador no frontend.
Servidor WebSocket com autenticação no handshake
A autenticação acontece antes de completar o upgrade HTTP para WebSocket. Se você autenticar depois, qualquer cliente anônimo consegue abrir uma conexão e consumir recursos do servidor até ser desconectado.
// server.ts
import { WebSocketServer, WebSocket } from "ws";
import { createServer } from "http";
import { verify, JwtPayload } from "jsonwebtoken";
const JWT_SECRET = process.env.JWT_SECRET!;
const PORT = Number(process.env.PORT) || 3001;
const httpServer = createServer();
const wss = new WebSocketServer({ noServer: true });
// Map de userId -> Set de conexões (um usuário pode ter múltiplas abas)
const userConnections = new Map<string, Set<WebSocket>>();
// Autenticação acontece no upgrade, ANTES de aceitar a conexão
httpServer.on("upgrade", (request, socket, head) => {
const url = new URL(request.url!, `http://${request.headers.host}`);
const token = url.searchParams.get("token");
if (!token) {
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
socket.destroy();
return;
}
try {
const payload = verify(token, JWT_SECRET) as JwtPayload & { userId: string };
wss.handleUpgrade(request, socket, head, (ws) => {
// Anexa userId ao objeto ws para uso posterior
(ws as any).userId = payload.userId;
wss.emit("connection", ws, request);
});
} catch {
socket.write("HTTP/1.1 401 Unauthorized\r\n\r\n");
socket.destroy();
}
});
wss.on("connection", (ws: WebSocket) => {
const userId = (ws as any).userId as string;
// Registra a conexão no map do usuário
if (!userConnections.has(userId)) {
userConnections.set(userId, new Set());
}
userConnections.get(userId)!.add(ws);
console.log(`Usuário ${userId} conectado. Total de conexões: ${userConnections.get(userId)!.size}`);
ws.on("close", () => {
const connections
---
Leia o artigo completo em [https://www.vivodecodigo.com.br/backend/websockets-notificacoes-tempo-real-nodejs-react](https://www.vivodecodigo.com.br/backend/websockets-notificacoes-tempo-real-nodejs-react)