Table of Contents
As notificações em tempo real tornaram-se uma pedra angular do design de aplicativos web modernos. Os usuários esperam feedback instantâneo quando os eventos ocorrem: uma nova mensagem de chat chega, um colega aprova um documento ou um alerta de servidor dispara. Construir esta funcionalidade em um aplicativo web JavaScript requer planejamento cuidadoso, os protocolos de comunicação corretos e design de UI pensativo. Este guia orienta você através da implementação de notificações em tempo real usando WebSockets e Eventos de Envio de Servidor (SSE), integrando-os com sistemas de backend como Directus, e garantindo uma experiência de usuário polida e pronta para produção.
Por que as notificações em tempo real importam
As notificações em tempo real eliminam a necessidade de atualização ou votação de páginas manuais, que drenam a largura de banda e degradam a experiência do usuário. Quando um usuário recebe um alerta instantâneo, ele fica engajado e pode reagir prontamente. Para plataformas SaaS, ferramentas de colaboração ou painéis de comércio eletrônico, essa imediateza impacta diretamente a produtividade e satisfação. Estudos mostram que a redução da latência da notificação de segundos para milissegundos pode aumentar a retenção do usuário em mais de 20% (]Nielsen Norman Group).
Além da experiência do usuário, as notificações em tempo real também permitem novos padrões de interação: fluxos de comentários ao vivo, cursores de edição colaborativos e feeds de eventos do lado do servidor. Escolher a camada de transporte certa é a primeira decisão técnica.
WebSocket: Comunicação Full-Duplex
WebSockets fornecem um canal bidirecional persistente entre um cliente e um servidor. Ao contrário do HTTP, a conexão permanece aberta após o aperto de mão inicial, permitindo que ambos os lados empurrem dados a qualquer momento. Isso torna o WebSockets ideal para aplicativos de chat, feeds financeiros ao vivo e jogos multiplayer — qualquer cenário em que a baixa latência, mensagens bidirecionais são críticas.
Estabelecendo uma conexão WebSocket no JavaScript
A API nativa do navegador torna a configuração da conexão direta. Você instancia um novo objeto com o URL do servidor (usando o esquema para conexões seguras). Depois, anexe ouvintes de eventos para , , , e .
const socket = new WebSocket('wss://api.directus.app/websocket');
socket.onopen = () => {
console.log('WebSocket connection established.');
// Optionally send an authentication token
socket.send(JSON.stringify({ type: 'auth', token: 'your-jwt' }));
};
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'notification') {
showToast(data.payload.message);
}
};
socket.onerror = (err) => {
console.error('WebSocket error:', err);
};
socket.onclose = (event) => {
console.warn('WebSocket closed:', event.code, event.reason);
// optional reconnect logic
};
Depois de estabelecer a conexão, você pode enviar mensagens formatadas por JSON e lidar com respostas no manipulador . O servidor deve suportar o protocolo WebSocket; muitos frameworks Node.js (por exemplo, ], ]) e backends CMS como o Directus offer built-in ou suporte WebSocket baseado em plugins.
Manuseamento da Reconexão e Batimentos Cardíacos
Um sistema robusto em tempo real deve lidar com interrupções de rede graciosamente. Implemente uma estratégia de reconexão que recua exponencialmente:
function connectWebSocket() {
const socket = new WebSocket('wss://api.directus.app/websocket');
let retryDelay = 1000;
socket.onclose = () => {
setTimeout(() => {
console.log('Reconnecting...');
connectWebSocket();
}, retryDelay);
retryDelay = Math.min(retryDelay * 2, 30000);
};
// ...other handlers
}
connectWebSocket();
Além disso, envie pings cardíacos periódicos (a cada 30-60 segundos) para detectar conexões antigas. Muitas bibliotecas WebSocket lidam com isso automaticamente, mas se você estiver usando a API bruta, defina um intervalo para enviar uma mensagem e espere uma resposta .
Eventos do servidor: Simplificação, transmissão de um caminho
O SSE é uma alternativa leve quando você só precisa do servidor para enviar dados para clientes sem precisar de mensagens cliente-a-server. O SSE usa HTTP padrão; o servidor responde com um cabeçalho e mantém a conexão aberta. O cliente lê o fluxo através da API .
O SSE é mais simples de implementar do que o WebSockets, funciona em HTTP/2 e reconecta automaticamente quando a conexão cai. No entanto, ele não suporta comunicação bidirecional, então é mais adequado para feeds de notícias, tickers de estoque ou alertas de sistema.
Usar o EventSource no Navegador
A interface do navegador é mínima:
const eventSource = new EventSource('/api/events?user_id=42');
eventSource.onopen = () => {
console.log('SSE connection opened.');
};
eventSource.addEventListener('notification', (event) => {
const data = JSON.parse(event.data);
displayNotification(data);
});
eventSource.onerror = (err) => {
console.error('EventSource error:', err);
// The browser will automatically attempt to reconnect
};
function displayNotification(data) {
// Update UI
}
No lado do servidor, você formata cada evento como linhas de texto:
event: notification
data: {"message":"Your report is ready","severity":"info"}
Note que a API só suporta GET requests e não pode enviar cabeçalhos personalizados. Se você precisar passar tokens de autenticação, anexá-los como parâmetros de consulta (use HTTPS para evitar expor o token).
WebSocket vs SSE: Escolhendo a abordagem correta
Ambas as tecnologias são capazes de lidar com notificações em tempo real, mas servem casos de uso diferentes:
| Feature | WebSocket | SSE |
|---|---|---|
| Direction | Bidirectional | Server → Client only |
| Auto‑reconnect | Must implement manually | Built‑in |
| Binary data | Yes (ArrayBuffer, Blob) | Text only (UTF‑8) |
| Browser support | Excellent (IE10+) | Good (no IE/Edge Legacy) |
| Complexity | Higher | Lower |
Se o cliente precisar enviar comandos ou dados de volta para o servidor (por exemplo, marcar uma notificação como lida), WebSocket é a escolha natural. Para feeds de notificação simples, SSE reduz o desenvolvimento em cima e é mais fácil de depurar porque usa cabeçalhos HTTP padrão.
Integrando notificações em tempo real com o Directus
Directus é um CMS sem cabeça que expõe uma API REST e GraphQL. Para adicionar recursos em tempo real, você pode aproveitar seu suporte ao WebSocket (introduzido no Directus 10.x) ou configurar um endpoint do SSE através de uma extensão personalizada. A API WebSocket permite que você se inscreva em alterações em coleções específicas, tornando-o direto para empurrar notificações quando um novo registro é criado ou atualizado.
Assinatura WebSocket em Directus
O endpoint WebSocket do Directus () aceita mensagens JSON para se inscrever, cancelar a subscrição ou autenticar. Por exemplo, para ouvir novas mensagens numa coleção :
const ws = new WebSocket('wss://cms.example.com/websocket');
ws.onopen = () => {
// Subscribe to changes on the notifications collection
ws.send(JSON.stringify({
type: 'subscribe',
collection: 'notifications',
query: { filter: { user_id: { _eq: currentUserId } } }
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === 'subscription' && msg.event === 'create') {
showNotification(msg.data);
}
};
Esta abordagem descarrega a complexidade da sincronização em tempo real para o CMS, enquanto o seu aplicativo JavaScript só precisa lidar com os dados recebidos. Para autenticação, envie um token na primeira mensagem WebSocket (como mostrado anteriormente).
Mostrando notificações na UI
Uma vez que você tenha os dados, a experiência do usuário depende de como você apresenta. As notificações de brindes estilo são o padrão mais comum: uma pequena popup, não-intrusiva que aparece no canto da tela e auto-desaparece após alguns segundos. Bibliotecas como Toastr, Notyf[, ou Soner[] fornecem componentes prontos para usar com marcação acessível e animação.
Alternativamente, crie um componente de notificação personalizado. Aqui está um exemplo mínimo usando o JavaScript de baunilha e CSS:
function showToast(message, type = 'info') {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
toast.setAttribute('role', 'alert');
document.getElementById('toast-container').appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
// CSS (simplified):
.toast {
padding: 12px 20px;
margin-bottom: 8px;
border-radius: 4px;
color: #fff;
opacity: 0.9;
transition: opacity 0.3s;
}
.toast-info { background: #007bff; }
.toast-error { background: #dc3545; }
.toast-success { background: #28a745; }
Certifique-se de que o recipiente está fixado no canto superior direito e que as torradas se empilham verticalmente. Use no recipiente para garantir que os leitores de tela anunciam novas notificações.
Preferências do usuário e gerenciamento de notificações
Nem todas as notificações são igualmente importantes. Permita que os usuários personalizem quais eventos eles querem receber e através de quais canais (in-app, email, push). Guarde as preferências na infraestrutura e filtre os eventos no servidor antes de puxá-los para o cliente. Por exemplo, um usuário pode desativar alertas de “novo comentário” mas manter alertas de “tarefa atribuída”.
No seu aplicativo JavaScript, busque periodicamente o perfil de preferência do usuário e ajuste os filtros de assinatura de acordo. Se usar o Directus WebSockets, você pode enviar uma consulta atualizada de assinatura quando as preferências mudarem.
Retirada para navegadores não suportados
Enquanto os navegadores modernos suportam amplamente WebSockets e SSE, ambientes antigos (por exemplo, Internet Explorer 11 para WebSockets, IE / Edge Legacy para SSE) podem exigir polifills ou estratégias de retorno. Uma abordagem comum:
- Detetar suporte com ou .
- Retalho de polling: Use um endpoint de polling longo que retorna novos eventos como JSON. O cliente solicita o endpoint a cada poucos segundos e processa quaisquer eventos pendentes.
- Abtração bibliográfica: Use uma biblioteca como que se desvanece de forma transparente do WebSocket para o longo polling HTTP.
Quando as sondagens, definir um intervalo razoável (por exemplo, 5-10 segundos) e retornar uma resposta vazia se nenhum evento estiver pendente. Para reduzir a carga, use cabeçalhos ou consultas baseadas em tempo.
Considerações sobre segurança
As conexões em tempo real introduzem vários vetores de segurança que devem ser abordados:
- Autenticate every connection. Para WebSockets, envie um JWT ou token de sessão na primeira mensagem. Para SSE, adicione um token como parâmetro de consulta (mas nunca no URL se você registrá-lo).
- Validate and hiitize all data before pushing it to the client. Mesmo que sua infraestrutura seja confiável, nunca produza conteúdo bruto gerado pelo usuário em uma notificação sem escapar.
- Use protocolos seguros (, ]) para prevenir ataques do homem no meio.
- Limitar conexões por usuário para evitar abusos. Directus expõe configurações de limite de taxa que você pode configurar.
- Não expor o estado interno do servidor através de mensagens WebSocket ou SSE. Devolve sempre apenas os dados que o utilizador está autorizado a ver.
Desempenho e Escalabilidade
À medida que o número de conexões simultâneas cresce, seu servidor deve gerenciá-las de forma eficiente. Considere estas otimizações:
- Use um servidor WebSocket dedicado (por exemplo, processo Node.js separado) e escale horizontalmente com um balanceador de carga que suporta sessões WebSocket pegajosas.
- Broadcast somente para usuários relevantes. Use salas ou canais baseados em ID de usuário, grupo ou filtro de assinatura para evitar enviar todos os eventos para cada cliente.
- Mensagens de compressão[. Para protocolos baseados em texto, habilitar deflate por mensagem (WebSocket) ou gzip (SSE sobre HTTP/2).
- Monitor connection health com métricas como conexões abertas, taxa de transferência de mensagens e taxa de erro. Ferramentas como Prometheus podem raspar isso do seu servidor.
- Considere o cache de eventos de envio de servidor. Com o SSE, você pode aproveitar os cabeçalhos de cache HTTP se o fluxo estiver estático por um período (embora as notificações sejam geralmente dinâmicas).
Juntando tudo: Um fluxo de trabalho completo
Para ilustrar um exemplo do mundo real, vamos combinar uma infraestrutura Directus com uma interface JavaScript que usa SSE para notificações.
- Backend (Extensão do Directus): Criar um endpoint personalizado em que verifica o token JWT do usuário, então envia novas notificações de uma fila (por exemplo, Redis pub/sub ou um gancho Directus que escreve para uma coleção ). O endpoint retorna .
- Frontend:] Ao carregar a página, autentique com Directus e abra um apontando para . Ouça ] eventos.
- Exibir: Cada notificação recebida é renderizada como um brinde usando um componente personalizado, com opções para descartar ou abrir o recurso relacionado.
- Preferências do usuário: Quando o usuário atualiza suas configurações de notificação através de um formulário, envie um POST para o endpoint do Directus. A infraestrutura atualiza o filtro de fluxo de eventos para essa sessão.
Esta arquitetura mantém o cliente magro e empurra o levantamento pesado para Directus e seu sistema de gancho.
Testando notificações em tempo real
Antes de implantar, teste completamente sua implementação:
- Teste de carga: Use ferramentas como Artilharia para simular centenas de conexões simultâneas WebSocket ou SSE. Meça latência e estabilidade de conexão.
- A tensão da rede: Use o Chrome DevTools para simular condições lentas 3G ou offline. Verifique se a lógica de reconexão funciona e se nenhuma notificação duplicada é enviada.
- Teste de cruzamento: Teste no Firefox, Safari, Chrome e Edge. Para SSE, teste no Safari (que não tem suporte completo à EventSource para eventos personalizados – você pode precisar usar um polifill).
- Casos de margem de segurança: Tentar conectar-se com tokens expirados, ou injetar JSON malformado para garantir que seus manipuladores de erro não intrudem o cliente.
Conclusão
As notificações em tempo real já não são um luxo; são uma expectativa de linha de base em aplicações web modernas. Ao alavancar WebSockets ou SSE, combinadas com uma infra-estrutura como Directus que fornece ganchos em tempo real, você pode entregar atualizações instantâneas sem sobrecarregar sua infraestrutura. Foque-se na personalização do usuário, graciosas falhas e segurança robusta para criar um sistema de notificação que se sinta perfeito e confiável.
Comece pequeno: implemente um brinde simples para um tipo de evento e depois expanda-se gradualmente para vários canais e preferências de usuário. A chave é iterar a experiência do usuário, mantendo o transporte subjacente eficiente e sustentável. Com as abordagens aqui descritas, você estará bem no seu caminho para uma funcionalidade em tempo real pronta para a produção.