
WebSockets na prática: quando usar, como implementar e onde quebra
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ério | Polling | SSE (Server-Sent Events) | WebSocket |
|---|---|---|---|
| Direção | Cliente → servidor | Servidor → cliente | Bidirecional |
| Transporte | HTTP repetido | HTTP/1.1 persistente (texto) | TCP após upgrade (binário ou texto) |
| Overhead por mensagem | Headers HTTP completos | Baixo (texto event-stream) | Muito baixo (2–14 bytes) |
| Reconexão automática | N/A (refaz request) | Sim, nativa no browser | Não; implementar no cliente |
| Proxies/firewalls | Sem problemas | Geralmente OK | Pode ser bloqueado; exige fallback |
| Caso de uso ideal | Atualização esporádica | Feeds, notificações, logs | Chat, 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.
// 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:
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:
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
- RFC 6455 — The WebSocket Protocol
- MDN — WebSocket API
- ws — biblioteca WebSocket para Node.js
- MDN — Server-Sent Events
Revisão editorial: publicado em . Última revisão em . Conteúdo educativo, sem patrocínio das ferramentas citadas.
Leia também

Serverless: quando funções serverless valem a pena (e quando viram armadilha)
AWS Lambda, Cloudflare Workers e Vercel Functions comparados: modelo de custo, cold starts, limites de execução e os workloads onde serverless brilha ou falha.

Core Web Vitals na prática: LCP, INP e CLS medidos e corrigidos
Guia técnico dos três Core Web Vitals: como medir com dados reais (CrUX/RUM), as causas mais comuns de LCP, INP e CLS ruins e as correções que funcionam.

Acessibilidade web (a11y) na prática: WCAG, ARIA e testes que funcionam
Guia técnico de acessibilidade: semântica HTML, quando (não) usar ARIA, contraste WCAG, navegação por teclado e testes automatizados com axe e Playwright.