3

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ériowsSocket.IOuWebSockets.js
ProtocoloWebSocket puro (RFC 6455)Protocolo próprio sobre WebSocket/pollingWebSocket puro
Overhead de payloadNenhum~50-100 bytes por mensagem (envelope de evento)Nenhum
Fallback HTTP long-pollingNãoSim, automáticoNão
Reconexão automática (client)ManualEmbutidaManual
Performance (mensagens/s em single thread)~40k~15k~100k+
Compatibilidade com proxy/CDNAlta (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)
Carregando publicação patrocinada...