Pular para o conteúdo
programação com IA

Como criar chats, notificações e dashboards ao vivo com WebSockets

Admin6 min de leitura
Como criar chats, notificações e dashboards ao vivo com WebSockets

Como criar chats, notificações e dashboards ao vivo com WebSockets

Resumo: Este artigo demonstra, de forma prática e detalhada, como usar WebSockets para construir aplicações que exigem comunicação em tempo real, como chats, notificações push e painéis de monitoramento. Abordaremos a arquitetura recomendada, questões de segurança, estratégias de escalabilidade e apresentaremos exemplos de código funcionais em Node.js e Python.

Tecnologia e Inovação

Introdução

A necessidade de interatividade instantânea tem impulsionado a adoção de WebSockets em aplicações modernas. Diferente das requisições HTTP tradicionais, que seguem o modelo request‑response, o WebSocket estabelece um canal bidirecional persistente entre cliente e servidor. Essa conexão permite a troca de mensagens com latência mínima, ideal para:

  • Chats onde cada mensagem deve aparecer imediatamente para todos os participantes.
  • Notificações push que avisam o usuário sobre eventos críticos (ex.: nova ordem, alerta de segurança).
  • Dashboards live que exibem métricas de sistemas, preço de ativos financeiros ou status de dispositivos IoT em tempo real.
Neste post, vamos percorrer todo o ciclo de desenvolvimento, desde a escolha da biblioteca até a implantação em produção, com foco em manutenibilidade e segurança.


1. Arquitetura básica de um sistema WebSocket

1.1 Componentes principais

ComponenteFunçãoTecnologias típicas
ClienteAbre a conexão, envia e recebe mensagens.JavaScript (browser), React Native, Flutter
Servidor WebSocketMantém sockets ativos, roteia mensagens e aplica lógica de negócios.ws (Node.js), websockets (Python), Socket.IO (abstração)
Broker de mensagens (opcional)Distribui mensagens entre múltiplas instâncias do servidor, garantindo broadcast eficiente.Redis Pub/Sub, NATS, RabbitMQ
Camada de autenticaçãoVerifica identidade antes de abrir o canal.JWT, OAuth 2.0, cookies seguros
MonitoramentoColeta métricas de latência, conexões ativas, erros.Prometheus, Grafana

Dica: Em ambientes com alta carga, separar o broker de mensagens do servidor de aplicação permite escalar horizontalmente sem perder consistência.

1.2 Fluxo de conexão

  • Handshake HTTP – O cliente envia um GET /ws com cabeçalhos Upgrade: websocket.
  • Negociação – O servidor aceita, estabelece o protocolo e devolve 101 Switching Protocols.
  • Troca de mensagens – A partir daí, os frames são enviados em formato binário ou texto.
  • Fechamento – Qualquer ponto pode encerrar a conexão com um frame de close.

  • 2. Implementando o servidor

    Vamos criar duas versões simples: uma em Node.js usando a biblioteca ws e outra em Python com websockets. Ambas suportam:

    • Autenticação via JWT.
    • Broadcast para todos os sockets conectados.
    • Heartbeat (ping/pong) para detectar conexões inativas.

    2.1 Node.js (arquivo server.js)

    // server.js
    

    const http = require('http'); const WebSocket = require('ws'); const jwt = require('jsonwebtoken');

    const SECRET = 'sua_chave_secreta';

    // Cria servidor HTTP puro (necessário para o handshake) const server = http.createServer();

    // Instancia o WebSocket Server const wss = new WebSocket.Server({ noServer: true });

    // Mapeia sockets autenticados const clients = new Set();

    function verifyToken(token) { try { return jwt.verify(token, SECRET); } catch (_) { return null; } }

    // Quando um cliente se conecta wss.on('connection', (ws, req, user) => { ws.user = user; // armazena dados do usuário clients.add(ws); console.log(🟢 Usuário ${user.id} conectado);

    // Envia mensagem de boas‑vindas ws.send(JSON.stringify({ type: 'welcome', message: Olá, ${user.name}! }));

    // Recebe mensagens do cliente ws.on('message', (data) => { const msg = JSON.parse(data); if (msg.type === 'chat') { // Broadcast para todos const payload = JSON.stringify({ type: 'chat', from: ws.user.name, text: msg.text, timestamp: Date.now(), }); for (const client of clients) { if (client.readyState === WebSocket.OPEN) client.send(payload); } } });

    // Detecta desconexão ws.on('close', () => { clients.delete(ws); console.log(🔴 Usuário ${user.id} desconectado); }); });

    // Tratamento do handshake e validação do token server.on('upgrade', (request, socket, head) => { const token = request.headers['sec-websocket-protocol']; const user = verifyToken(token); if (!user) { socket.write('HTTP/1.1 401 Unauthorized\r \r '); socket.destroy(); return; }

    wss.handleUpgrade(request, socket, head, (ws) => { wss.emit('connection', ws, request, user); }); });

    server.listen(8080, () => console.log('🚀 Servidor WebSocket rodando na porta 8080'));

    Pontos de atenção

    • O token JWT é passado no cabeçalho Sec-WebSocket-Protocol. Essa prática evita expor credenciais na URL.
    • O heartbeat padrão do ws já envia ping/pong a cada 30 s; pode ser configurado via ws.isAlive.

    2.2 Python (arquivo server.py)

    # server.py
    

    import asyncio import json import jwt import websockets

    SECRET = "sua_chave_secreta" connected = set()

    def verify_token(token: str): try: return jwt.decode(token, SECRET, algorithms=["HS256"]) except jwt.InvalidTokenError: return None

    async def handler(websocket, path): # Primeiro frame deve conter o token token_msg = await websocket.recv() token_data = json.loads(token_msg) user = verify_token(token_data.get("token")) if not user: await websocket.close(code=4001, reason="Token inválido") return

    # Armazena usuário na conexão websocket.user = user connected.add(websocket) print(f"🟢 Usuário {user['id']} conectado")

    # Mensagem de boas‑vindas await websocket.send(json.dumps({ "type": "welcome", "message": f"Olá, {user['name']}!" }))

    try: async for message in websocket: data = json.loads(message) if data["type"] == "chat": payload = json.dumps({ "type": "chat", "from": websocket.user["name"], "text": data["text"], "timestamp": int(asyncio.get_event_loop().time() * 1000) }) # Broadcast await asyncio.wait([ws.send(payload) for ws in connected if ws.open]) finally: connected.remove(websocket) print(f"🔴 Usuário {user['id']} desconectado")

    Configura heartbeat automático (ping a cada 20s)

    start_server = websockets.serve( handler, "0.0.0.0", 8765, ping_interval=20, ping_timeout=10, )

    asyncio.get_event_loop().run_until_complete(start_server) print("🚀 Servidor Python WebSocket escutando na porta 8765") asyncio.get_event_loop().run_forever()

    Observações

    • O cliente envia um JSON contendo o token antes de iniciar a troca de mensagens.
    • O parâmetro ping_interval garante que conexões inativas sejam fechadas automaticamente.


    3. Cliente web: chat, notificações e dashboard

    A seguir, um exemplo de página HTML que:

  • Abre a conexão usando o token JWT.
  • Escuta mensagens de diferentes tipos (chat, notification, metric).
  • Atualiza a UI em tempo real.
  • <!DOCTYPE html>
    

    <html lang="pt-BR"> <head> <meta charset="UTF-8"> <title>Chat & Dashboard em Tempo Real</title> <style> body { font-family: Arial, sans-serif; margin: 2rem; } #log { border: 1px solid #ccc; height: 300px; overflow-y: auto; padding: .5rem; } #metrics { margin-top: 1rem; } .msg { margin: .2rem 0; } .notif { color: #0066cc; } </style> </head> <body> <h1>💬 Chat em tempo real</h1> <div id="log"></div> <input id="input" placeholder="Digite sua mensagem..." autocomplete="off"/> <button id="sendBtn">Enviar</button>

    <h2>📊 Dashboard de Métricas</h2> <div id="metrics"> <p>CPU: <span id="cpu">-</span>%</p> <p>Memória: <span id="mem">-</span>%</p> </div>

    <script> // Simula obtenção de JWT (em produção, viria do login) const jwtToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." const ws = new WebSocket(ws://localhost:8080, jwtToken);

    const log = document.getElementById('log'); const input = document.getElementById('input'); const sendBtn = document.getElementById('sendBtn');

    ws.onopen = () => addMsg('✅ Conexão estabelecida');

    ws.onmessage = (event) => { const data = JSON.parse(event.data); switch (data.type) { case 'welcome': addMsg(🤖 ${data.message}); break; case 'chat': addMsg(<strong>${data.from}:</strong> ${data.text}); break; case 'notification': addMsg(<span class="notif">🔔 ${data.text}</span>); break; case 'metric': document.getElementById('cpu').textContent = data.cpu; document.getElementById('mem').textContent = data.mem; break; } };

    ws.onclose = () => addMsg('❌ Conexão encerrada');

    sendBtn.onclick = () => { const text = input.value.trim(); if (!text) return; ws.send(JSON.stringify({ type: 'chat', text })); input.value = ''; };

    function addMsg(html) { const p = document.createElement('p'); p.className = 'msg'; p.innerHTML = html; log.appendChild(p); log.scrollTop = log.scrollHeight; } </script> </body> </html>

    Como funciona

    • O token JWT é passado como subprotocol no construtor do WebSocket. O servidor o valida antes de

    Artigos relacionados