Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Distinguir quem inicia a comunicação e em que direção os dados fluem em cada opção
- Escolher entre WebSocket, SSE e webhook conforme o caso de uso
- Ver um exemplo mínimo em Node.js das três técnicas
Uma requisição HTTP normal é uma pergunta com resposta: o cliente pergunta, o servidor responde e a conversa termina. Quando você precisa que algo chegue sem perguntar a cada poucos segundos (uma mensagem de chat, um pagamento aprovado, um preço que mudou), aparecem três opções: WebSocket, Server-Sent Events (SSE) e webhooks.
Elas se parecem no resultado, mas resolvem problemas diferentes. A pergunta que organiza tudo é: quem fala com quem, e em que direção?
O que é cada uma?#
WebSocket é um canal bidirecional sobre uma única conexão TCP. Ele começa como uma requisição HTTP com Upgrade, o servidor responde 101 Switching Protocols e, daí em diante, cliente e servidor trocam mensagens quando quiserem. Usa os esquemas ws:// e wss:// (este último, com TLS). É definido na RFC 6455. Mais detalhes em O que é WebSocket.
SSE é uma resposta HTTP que não termina. O navegador abre a conexão com EventSource, o servidor responde com Content-Type: text/event-stream e vai escrevendo eventos de texto. A informação só viaja do servidor para o cliente.
Webhook não é um protocolo, é um padrão: um serviço externo (como Stripe ou GitHub) faz uma requisição HTTP POST para uma URL sua quando um evento acontece. É comunicação entre servidores, sem navegador no meio.
Quais são as diferenças?#
| WebSocket | SSE | Webhook | |
|---|---|---|---|
| Direção | Nos dois sentidos | Servidor para o cliente | Serviço externo para o seu servidor |
| Quem inicia | O cliente abre o canal | O cliente abre a conexão | O serviço chama a sua URL |
| Conexão | Persistente | Persistente | Uma requisição por evento |
| Formato | Texto ou binário | Texto UTF-8 | Normalmente JSON |
| Reconexão | Você programa | Automática no navegador | Depende do serviço emissor |
| Cliente típico | Navegador, app, outro servidor | Navegador | Outro servidor |
Dois detalhes práticos do SSE: sobre HTTP/1.1, o navegador limita a 6 conexões abertas por domínio (por navegador, não por aba), enquanto com HTTP/2 o limite negociado por padrão é de 100 streams. E, como o EventSource reconecta sozinho, o servidor pode ajustar a espera com o campo retry.
Quando escolher WebSocket?#
Quando o cliente também envia dados com frequência e você precisa de baixa latência nos dois sentidos: chats, jogos multiplayer, edição colaborativa, cursores compartilhados. Se só o servidor fala, WebSocket é mais do que você precisa.
Em troca, você perde parte do que o HTTP já resolve: você mesmo cuida da reconexão, dos batimentos (ping/pong para detectar conexões mortas) e da autenticação das mensagens.
// npm install ws
import { WebSocketServer } from "ws";
const wss = new WebSocketServer({ port: Number(process.env.PORT) || 8080 });
wss.on("connection", (socket) => {
socket.on("message", (data) => {
// repassa para todos os clientes conectados
for (const client of wss.clients) {
if (client.readyState === client.OPEN) client.send(data.toString());
}
});
});No navegador: const ws = new WebSocket("wss://seu-dominio.com"); ws.onmessage = (e) => console.log(e.data);. Para colocar esse servidor no ar, veja como hospedar um servidor WebSocket.
Quando escolher SSE?#
Quando você só precisa empurrar dados para o navegador: notificações, progresso de uma tarefa, um placar ao vivo, a resposta de um modelo de IA que chega em pedaços. É HTTP puro, não precisa de biblioteca no cliente e o navegador reconecta sozinho.
// npm install express@5
import express from "express";
const app = express();
app.get("/eventos", (req, res) => {
res.set({
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
Connection: "keep-alive",
});
res.flushHeaders();
const timer = setInterval(() => {
res.write(`event: tick\ndata: ${JSON.stringify({ hora: new Date() })}\n\n`);
}, 1000);
req.on("close", () => clearInterval(timer));
});
app.listen(Number(process.env.PORT) || 3000);const fonte = new EventSource("/eventos");
fonte.addEventListener("tick", (e) => console.log(JSON.parse(e.data)));Cada mensagem termina com uma linha em branco. Os campos reconhecidos são event, data, id e retry. Se o cliente precisar enviar algo, use uma requisição fetch separada: a combinação de SSE com REST resolve muitos apps que parecem pedir WebSocket.
Quando escolher um webhook?#
Quando outro serviço precisa avisar o seu backend: um pagamento confirmado, um push num repositório, uma mensagem recebida. Você evita consultar a API dele a cada minuto (polling) e recebe o evento na hora. Para o caso do Discord, veja webhook vs bot.
O seu endpoint precisa ser público, responder rápido com um 2xx e verificar a assinatura, porque qualquer pessoa pode fazer um POST para a sua URL. O GitHub, por exemplo, assina o corpo com HMAC-SHA256 no cabeçalho X-Hub-Signature-256 e recomenda uma comparação de tempo constante.
import crypto from "node:crypto";
import express from "express";
const app = express();
// o HMAC é calculado sobre o corpo cru, não sobre o JSON já interpretado
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
if (!Buffer.isBuffer(req.body)) return res.sendStatus(415); // sem corpo JSON
const esperado =
"sha256=" +
crypto.createHmac("sha256", process.env.WEBHOOK_SECRET).update(req.body).digest("hex");
const recebido = req.get("X-Hub-Signature-256") ?? "";
const a = Buffer.from(esperado);
const b = Buffer.from(recebido);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.sendStatus(401);
}
const evento = JSON.parse(req.body.toString());
console.debug("evento recebido", evento.action);
res.sendStatus(204);
});
app.listen(Number(process.env.PORT) || 3000);O nome do cabeçalho e o algoritmo mudam de serviço para serviço: confira a documentação dele.
Dá para combinar?#
Dá, e é o comum. Um caso típico: um provedor de pagamentos avisa o seu servidor com um webhook de pagamento concluído, e o seu servidor repassa ao navegador do usuário com SSE ou WebSocket para a tela mudar sem recarregar. O webhook leva o dado até o seu backend; SSE ou WebSocket o levam até o cliente.
Regra curta: se o destino é um navegador que só escuta, SSE. Se o navegador também fala muito, WebSocket. Se o destino é o seu servidor e o emissor é um serviço externo, webhook. Não existe vencedor universal. Se o que você quer é consultar ou alterar dados, uma API REST continua sendo a base.
Como fazer isso na Square Cloud#
Os três padrões precisam de um processo sempre ligado com uma URL pública, e é isso que uma aplicação web na Square Cloud oferece: containers sem modo de suspensão e um subdomínio *.squareweb.app com HTTPS em todos os planos. A rede suporta WebSockets, então o wss:// do exemplo funciona nesse subdomínio, e o proxy deixa WebSocket e SSE passarem sem buffer e sem cortar conexões longas.
Para o webhook, a URL da sua aplicação é a que você cadastra no serviço emissor. Guarde o segredo da assinatura como variável de ambiente no painel, não no código. Você pode usar Node.js, Python, Go e outros dos runtimes disponíveis.
O plano Hobby começa em R$ 12,49 por mês com 1 GB de RAM, e a RAM é compartilhada entre todas as suas aplicações. Para publicar uma API completa, comece por Como hospedar uma API e confira o checklist de produção. A página de hospedagem de APIs resume o que você precisa.
Hospedagem de APIs
APIs em containers sempre ligados, sem cold start
Perguntas frequentes
SSE é mais rápido que WebSocket?
Não existe uma diferença de velocidade que decida a escolha. Depois de abertos, os dois enviam eventos na hora. A diferença real é a direção: SSE só vai do servidor para o cliente, WebSocket vai nos dois sentidos.
Posso usar um webhook para atualizar uma página em tempo real?
Não diretamente. Um webhook chega ao seu servidor, não ao navegador. O seu servidor precisa repassar o dado ao navegador com SSE ou WebSocket.
WebSocket substitui as requisições HTTP normais?
Não. Para consultar ou alterar recursos, uma API REST continua sendo o mais simples. WebSocket é para quando você precisa de mensagens frequentes nos dois sentidos.
SSE reconecta sozinho se a conexão cair?
Sim. O EventSource tenta de novo automaticamente, e o servidor pode indicar o tempo de espera com o campo retry. Com WebSocket, você mesmo programa a reconexão.
Como sei que um webhook vem do serviço real?
Verificando a assinatura. Muitos serviços enviam um HMAC do corpo num cabeçalho, como o X-Hub-Signature-256 do GitHub, e você deve compará-lo com o seu segredo usando uma comparação de tempo constante.
Mais em APIs
Ver todos os 15 artigos- Como hospedar uma APIHospedar uma API é rodar o servidor HTTP 24 horas num lugar com IP público e HTTPS. Veja o passo a passo com Node.js e Python, testes e erros comuns.
- Como hospedar uma aplicação Node.jsPara hospedar uma aplicação Node.js, prepare o package.json, leia porta e segredos do ambiente, escolha uma versão LTS e rode com node. Veja o passo a passo.
- Como hospedar FastAPI, Flask ou DjangoPara hospedar FastAPI, Flask ou Django, rode a aplicação com um servidor de produção (Uvicorn ou Gunicorn) em 0.0.0.0. Veja comandos, ajustes do Django e erros.
- Como hospedar um script ou API em PythonPara hospedar um script ou API em Python, fixe a versão, isole dependências em um venv, leia segredos do ambiente e trate o SIGTERM. Passo a passo com código.