icardb
WebSockets na prática: quando usar, como implementar e onde quebra
Voltar para artigosPROGRAMAÇÃO

WebSockets na prática: quando usar, como implementar e onde quebra

Por Lucas Mendes 7 min de leitura

Chat, cotações, dashboards ao vivo, edição colaborativa: toda vez que o servidor precisa empurrar dados sem o cliente pedir, entra em cena comunicação em tempo real. WebSocket é a ferramenta mais conhecida, mas não é a única — nem sempre a melhor. Este artigo cobre o protocolo, uma implementação completa com a biblioteca ws, reconexão no cliente e uma comparação honesta com Server-Sent Events e polling.

O que o protocolo WebSocket resolve

HTTP é request-response: o cliente pergunta, o servidor responde, a conexão se fecha (ou fica ociosa). Para o servidor notificar o cliente, as opções clássicas eram polling (cliente pergunta a cada N segundos) ou long-polling (servidor segura a resposta até ter novidade). WebSocket, definido na RFC 6455, resolve isso com um upgrade de conexão: a sessão começa como HTTP, faz um handshake e passa a ser um canal TCP persistente, full-duplex, com frames leves de 2 a 14 bytes de overhead.

CritérioPollingSSE (Server-Sent Events)WebSocket
DireçãoCliente → servidorServidor → clienteBidirecional
TransporteHTTP repetidoHTTP/1.1 persistente (texto)TCP após upgrade (binário ou texto)
Overhead por mensagemHeaders HTTP completosBaixo (texto event-stream)Muito baixo (2–14 bytes)
Reconexão automáticaN/A (refaz request)Sim, nativa no browserNão; implementar no cliente
Proxies/firewallsSem problemasGeralmente OKPode ser bloqueado; exige fallback
Caso de uso idealAtualização esporádicaFeeds, notificações, logsChat, jogos, colaboração

Se o fluxo de dados é unidirecional (servidor → cliente), SSE é mais simples, funciona sobre HTTP comum e reconecta sozinho. WebSocket só se justifica quando o cliente também precisa enviar mensagens frequentes.

Servidor WebSocket mínimo com Node.js

A biblioteca ws é a referência em Node. O exemplo abaixo é um servidor de broadcast funcional: toda mensagem recebida de um cliente é enviada a todos os demais conectados.

ts
// npm install ws
import { WebSocketServer, WebSocket } from "ws";

const wss = new WebSocketServer({ port: 8080 });

wss.on("connection", (socket: WebSocket, req) => {
  const ip = req.socket.remoteAddress;
  console.log(`cliente conectado: ${ip}`);

  socket.on("message", (data: Buffer) => {
    const texto = data.toString();
    // broadcast para todos, exceto o remetente
    for (const cliente of wss.clients) {
      if (cliente !== socket && cliente.readyState === WebSocket.OPEN) {
        cliente.send(texto);
      }
    }
  });

  socket.on("close", () => console.log(`cliente desconectado: ${ip}`));
  socket.on("error", (err) => console.error("erro no socket:", err));
});

console.log("WebSocket escutando em ws://localhost:8080");

Cliente no navegador com reconexão

Diferente de SSE, a API nativa de WebSocket do browser não reconecta automaticamente. Em produção, conexões caem o tempo todo (troca de rede, proxy com idle timeout, deploy do servidor). Um wrapper mínimo com backoff exponencial resolve:

ts
function conectarWebSocket(url: string, onMensagem: (dados: string) => void) {
  let tentativas = 0;
  let socket: WebSocket;

  function conectar() {
    socket = new WebSocket(url);

    socket.onopen = () => {
      tentativas = 0; // zera o backoff ao conectar
      console.log("ws conectado");
    };

    socket.onmessage = (evento) => onMensagem(evento.data as string);

    socket.onclose = () => {
      const espera = Math.min(1000 * 2 ** tentativas, 30_000); // teto de 30s
      tentativas++;
      console.log(`ws caiu; reconectando em ${espera}ms`);
      setTimeout(conectar, espera);
    };

    socket.onerror = () => socket.close(); // força o fluxo de onclose
  }

  conectar();
  return { enviar: (msg: string) => socket.readyState === WebSocket.OPEN && socket.send(msg) };
}

Heartbeat: o detalhe que derruba conexões em produção

Proxies e load balancers (nginx, Cloudflare, ALB) encerram conexões TCP ociosas — normalmente após 60 segundos sem tráfego. A solução é ping/pong: o servidor envia um ping a cada 30s e encerra clientes que não respondem. A biblioteca ws expõe isso diretamente:

ts
const intervalo = setInterval(() => {
  for (const socket of wss.clients) {
    if ((socket as any).vivo === false) return socket.terminate();
    (socket as any).vivo = false;
    socket.ping();
  }
}, 30_000);

wss.on("connection", (socket) => {
  (socket as any).vivo = true;
  socket.on("pong", () => ((socket as any).vivo = true));
});

wss.on("close", () => clearInterval(intervalo));

Escalando além de um processo

Um WebSocket é estado em memória: o servidor que detém a conexão é o único que pode enviar mensagens a ela. Com múltiplas réplicas, você precisa de: (1) sticky sessions no load balancer, para o upgrade cair sempre no mesmo processo; e (2) um barramento pub/sub (Redis é o padrão) para que uma mensagem publicada na réplica A chegue aos clientes conectados na réplica B. Bibliotecas como Socket.IO já embutem esse adaptador de Redis.

Conclusão

WebSocket é a ferramenta certa para comunicação bidirecional frequente — chat, jogos, colaboração em tempo real. Para fluxos só de saída, SSE entrega o mesmo resultado com menos código e reconexão grátis. Em qualquer caso, reconexão com backoff, heartbeat e uma estratégia de escala horizontal são requisitos de produção, não opcionais.

Perguntas frequentes

+WebSocket funciona atrás de proxies e firewalls corporativos?

Na maioria dos casos sim, especialmente sobre TLS (wss://, porta 443). Alguns proxies antigos bloqueiam o header Upgrade. A prática recomendada é ter um fallback de long-polling — bibliotecas como Socket.IO fazem isso automaticamente.

+Qual a diferença entre ws e Socket.IO?

ws é uma implementação enxuta do protocolo WebSocket. Socket.IO é uma camada acima que adiciona reconexão automática, fallback para long-polling, salas (rooms) e acknowledgements — mas exige o cliente Socket.IO, pois não é WebSocket puro no handshake.

+WebSocket é seguro?

O protocolo em si não autentica ninguém. Use sempre wss:// (TLS), valide a origem no handshake (header Origin), autentique via token no momento do upgrade e proteja contra CSWSH (Cross-Site WebSocket Hijacking).

+HTTP/2 ou HTTP/3 substituem WebSocket?

Não para o caso bidirecional. HTTP/2 multiplexa requests, mas o modelo continua request-response. A WebTransport API sobre HTTP/3 é a candidata moderna a sucessora para casos de baixa latência, mas o suporte de browsers e servidores ainda é parcial em 2026.

Fontes consultadas

Revisão editorial: publicado em . Última revisão em . Conteúdo educativo, sem patrocínio das ferramentas citadas.

Crédito da imagem: Foto: Lucas Mendes / Gerado por IA (Licença Editorial)

Leia também