WebSockets, SSE ou polling: qual é que o seu caso pede
"Quero que a página se atualize sozinha" tem três respostas possíveis, e escolher a mais poderosa por defeito é a forma mais comum de complicar um problema simples.
1. Polling: perguntar de vez em quando
setInterval(async () => {
const resposta = await fetch('/api/notificacoes');
mostrar(await resposta.json());
}, 30000);Feio, e frequentemente suficiente. Funciona em qualquer sítio, atravessa qualquer proxy, e não tem estado nenhum no servidor. Para dados que mudam de minuto a minuto, é a resposta certa — e a que se consegue depurar com o separador de rede aberto.
2. SSE: o servidor fala, o cliente ouve
const fonte = new EventSource('/api/eventos');
fonte.addEventListener('message', (evento) => {
mostrar(JSON.parse(evento.data));
});// No servidor: HTTP normal, que não fecha
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.write(`data: ${JSON.stringify({ novos: 3 })}\n\n`);É HTTP simples, numa direção só. E traz de graça a parte chata: se a ligação cair, o EventSource volta a ligar sozinho. Serve notificações, barras de progresso, resultados a chegar — tudo o que seja o servidor a empurrar.
3. WebSockets: os dois lados falam
const ligacao = new WebSocket('wss://exemplo.pt/sala');
ligacao.addEventListener('message', (evento) => mostrar(evento.data));
ligacao.send(JSON.stringify({ escrevendo: true }));Protocolo próprio, ligação permanente nos dois sentidos, latência mínima. É o que um chat, um jogo ou um editor colaborativo precisam — e traz consigo o que uma ligação com estado implica: reconexão à mão, escala mais difícil, proxies a configurar.
4. A pergunta que decide
Muda de minuto a minuto e ninguém morre por esperar → polling.
É o servidor a avisar, e o cliente só ouve → SSE.
Os dois lados enviam, e cada milissegundo conta → WebSockets.
Na dúvida entre os dois últimos, o SSE é quase sempre o suficiente — e é o único dos três que se depura a olhar para uma resposta HTTP normal.