Quando precisamos enviar dados do servidor para o cliente em tempo real, como notificações ou painéis de controle, uma abordagem comum é o polling. No entanto, o polling pode gerar uma sobrecarga desnecessária na rede e no servidor, pois o cliente precisa constantemente perguntar se há novas informações.
Server-Sent Events (SSE) oferece uma alternativa mais eficiente. Com o SSE, o servidor pode enviar dados para o cliente através de uma conexão persistente. Isso elimina a necessidade do cliente ficar solicitando informações constantemente, reduzindo a latência e otimizando o uso de recursos.
Ao contrário do polling, que estabelece várias requisições HTTP, o SSE utiliza uma única conexão para enviar múltiplos eventos, tornando-o ideal para aplicações que exigem atualizações em tempo real e comunicação unidirecional do servidor para o cliente.
Neste texto será apresentado um exemplo prático de implementação de SSE utilizando Node.js e um pouco de HTML. O objetivo será enviar notificações para o frontend em tempo real, que por sua vez, irá exibir os detalhes para o usuário.
Server-Sent Events (SSE): uma introdução
O Server-Sent Events (SSE) é uma tecnologia que permite que servidores enviem dados em tempo real para clientes web de forma eficiente. Essa comunicação unidirecional ocorre através de uma única conexão HTTP persistente.
Como funciona o SSE
Requisição: O cliente inicia uma requisição HTTP para um endpoint específico no servidor.
Resposta: O servidor responde com um status 200 OK e um cabeçalho Content-Type: text/event-stream, indicando que se trata de uma conexão SSE. A conexão permanece aberta.
Eventos: O servidor pode enviar dados para o cliente a qualquer momento.
Cliente: O cliente escuta esses eventos e os processa de acordo com sua lógica.
Este canal de comunicação permanece aberto, permitindo que o servidor envie mensagens para o cliente através de uma única requisição HTTP, diferentemente do polling, que exige múltiplas requisições. A seguir, apresentamos um projeto que demonstra essa funcionalidade na prática.
Exemplo de SSE com Node.js e Express
A título de estudo, criei um pequeno projeto que roda no Node.js com o framework Express. Veja a seguir os detalhes:
# Iniciando o projeto
npm init -y
# Instalando o Express
npm i express
Após criar a estrutura do projeto, adicionei 3 arquivos:
index.js
index.html
notificacoes.js
Gerenciando as conexões dos usuários (notificacoes.js)
A classe Notificacoes é a responsável por guardar as conexões de cada usuário e possibilitar o envio de mensagens para um usuário específico ou todos conectados.
💡
A aplicação do prefixo # nos métodos/campos acima, tornam o recurso privado em JavaScript. Para saber mais, acesse este link.
Criando os endpoints e enviando mensagens (index.js)
No arquivo index.js, temos a configuração de 2 enpoints e também de um simulador de envio de mensagens. Deixei o código comentado para facilitar o entendimento:
Construindo a página de testes (index.html)
Por fim, o arquivo index.html serve para testar a funcionalidade. O código é básico e direto, sem incluir validações ou melhorias na experiência do usuário, pois o foco deste projeto é puramente didático.
Executando e testando o projeto
No cenário simulado, há dois usuários conectados: USUARIO_AAA e USUARIO_BBB, sendo que o USUARIO_BBB tem duas abas do navegador abertas.
Na imagem abaixo, você pode ver que algumas mensagens são enviadas para todos os usuários e conexões, enquanto outras são direcionadas exclusivamente para um usuário específico.
Um outro ponto de observação é no DevTools. Na aba "Network" (Rede), você pode notar que uma requisição permanece aberta, sendo essa a requisição SSE, que permite ao backend enviar mensagens em tempo real.
Como exemplo do mundo real, podemos observar uma requisição desse tipo na versão web do X (Twitter, ago/2024). Para visualizar, basta abrir o site no navegador e inspecionar o DevTools, conforme ilustrado na imagem abaixo:
Código fonte do exemplo
Abaixo deixo o link do projeto no Github. Após efetuar o clone e instalar as dependências, basta executar o comando npm start para iniciar o projeto.
Conclusão
Podemos destacar a simplicidade de implementação. Tanto o servidor quanto o cliente podem ser implementados com relativa facilidade. Os SSE não requerem bibliotecas adicionais para muitas linguagens de programação, pois são baseados em tecnologias web padrão, como HTTP e JavaScript.
Embora os navegadores modernos suportem SSE, algumas versões mais antigas podem não ser totalmente compatíveis, então certifique-se nos seus requisitos quais serão as versões de navegadores atendidas.
Um outro ponto importante a considerar é que, durante os testes, percebi que a classe nativa EventSource do JavaScript não permite o envio de cabeçalhos personalizados (ago/2024). Isso significa que, em cenários onde é necessário, por exemplo, incluir o cabeçalho Authorization, essa classe não atenderá às necessidades. Nesses casos, é recomendável buscar bibliotecas alternativas que ofereçam suporte a essa funcionalidade ou alterar a forma como essas informações são enviadas.
Para finalizar, Server-Sent Events são uma excelente opção para casos de uso em que a comunicação unidirecional do servidor para o cliente é suficiente. Eles oferecem uma alternativa simples aos WebSockets e podem ser uma ótima escolha para implementações de tempo real que não requerem uma troca constante de dados entre servidor e cliente como no polling. Com a vantagem de serem nativamente suportados pelos navegadores, os SSE são uma ferramenta valiosa para adicionar atualizações em tempo real às aplicações web.