WebSocket em JavaScript: criando aplicações em tempo real no Node.js

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

WebSocket em JavaScript: criando aplicações em tempo real com Node.js



A web moderna exige respostas instantâneas. Os usuários esperam que as mensagens no chat sejam entregues em milissegundos, as cotações de ações sejam atualizadas sem recarregar a página e as notificações cheguem em tempo real. A tecnologia WebSocket em JavaScript resolve esse problema, fornecendo uma conexão bidirecional permanente entre o cliente e o servidor. Neste artigo, vamos explorar como usar WebSocket no ambiente Node.js para criar aplicações em tempo real rápidas e escaláveis.



O que é WebSocket e por que ele é necessário?



O protocolo HTTP tradicional funciona no princípio de "requisição-resposta": o cliente envia uma requisição, o servidor responde e a conexão é encerrada. Para obter novos dados, o cliente precisa consultar o servidor constantemente (polling) ou usar requisições HTTP longas (long polling). Isso é ineficiente, cria carga excessiva e aumenta a latência.



WebSocket (RFC 6455) é um protocolo que estabelece uma conexão duplex permanente através de um único canal TCP. Após o handshake via HTTP, o servidor e o cliente podem enviar dados um para o outro a qualquer momento, sem cabeçalhos adicionais. Isso torna o WebSocket a solução ideal para:



  • Chats e mensageiros
  • Jogos online e edição colaborativa
  • Cotações de bolsa e dashboards financeiros
  • Notificações push e monitoramento
  • Transmissão de dados em fluxo (IoT, logs)


Instalação e configuração do servidor WebSocket no Node.js



Para trabalhar com WebSocket no lado do servidor, usaremos a biblioteca ws — a implementação mais popular e confiável para Node.js. Vamos instalá-la via npm:



npm install ws


Vamos criar um servidor WebSocket simples. Primeiro, importamos o módulo e criamos uma instância do servidor na porta 8080:



const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) { console.log('Novo cliente conectado');

// Envia uma mensagem de boas-vindas ao cliente ws.send('Bem-vindo ao servidor WebSocket!');

// Processa mensagens recebidas ws.on('message', function incoming(message) { console.log('Recebido: %s', message); // Responde para todos os clientes conectados wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(`Eco: ${message}`); } }); });

// Processa a desconexão do cliente ws.on('close', function close() { console.log('Cliente desconectado'); });

// Processa erros ws.on('error', function error(err) { console.error('Erro no WebSocket:', err); });});

console.log('Servidor WebSocket iniciado em ws://localhost:8080');


Este código cria um servidor echo simples: qualquer mensagem enviada pelo cliente será retransmitida para todos os usuários conectados. Observe a verificação readyState — ela garante que não tentamos enviar dados para uma conexão fechada.



Parte cliente do WebSocket no navegador



No lado do cliente (navegador), o WebSocket é um objeto nativo — nenhuma biblioteca adicional é necessária. Vamos nos conectar ao nosso servidor e implementar um chat simples:



// Cria uma conexão WebSocketconst socket = new WebSocket('ws://localhost:8080');

// Manipulador de abertura da conexãosocket.addEventListener('open', function (event) { console.log('Conexão estabelecida'); socket.send('Olá, servidor!');});

// Manipulador de recebimento de mensagemsocket.addEventListener('message', function (event) { const messagesDiv = document.getElementById('messages'); const messageElement = document.createElement('div'); messageElement.textContent = event.data; messagesDiv.appendChild(messageElement);});

// Manipulador de errosocket.addEventListener('error', function (event) { console.error('Erro no WebSocket:', event);});

// Manipulador de fechamento da conexãosocket.addEventListener('close', function (event) { console.log('Conexão fechada');});


Este código estabelece uma conexão com o servidor WebSocket, envia uma mensagem de saudação e exibe todas as mensagens recebidas na página. O WebSocket gerencia automaticamente a reconexão e o heartbeat, tornando a comunicação confiável mesmo em condições de rede instáveis.



Envio de dados estruturados: JSON sobre WebSocket



Na prática, raramente enviamos apenas strings simples. Normalmente, trocamos objetos de dados estruturados. O formato mais conveniente para isso é o JSON. Vamos modificar nosso servidor para processar mensagens JSON:



const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

wss.on('connection', function connection(ws) { console.log('Novo cliente conectado');

ws.on('message', function incoming(data) { try { const message = JSON.parse(data); console.log('Mensagem recebida:', message);

// Processa diferentes tipos de mensagens switch(message.type) { case 'chat': // Broadcast da mensagem de chat para todos os clientes wss.clients.forEach(function each(client) { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'chat', user: message.user, text: message.text, timestamp: Date.now() })); } }); break;

case 'join': // Notifica outros usuários sobre novo participante wss.clients.forEach(function each(client) { if (client !== ws && client.readyState === WebSocket.OPEN) { client.send(JSON.stringify({ type: 'system', text: `${message.user} entrou no chat` })); } }); break;

default: console.log('Tipo de mensagem desconhecido:', message.type); } } catch (e) { console.error('Erro ao processar JSON:', e); } });});

console.log('Servidor WebSocket JSON iniciado em ws://localhost:8080');


No lado do cliente, enviamos dados estruturados usando JSON.stringify() e processamos as respostas com JSON.parse():



const socket = new WebSocket('ws://localhost:8080');

// Envia uma mensagem de chatfunction sendChatMessage(user, text) { const message = { type: 'chat', user: user, text: text }; socket.send(JSON.stringify(message));}

// Processa mensagens recebidassocket.addEventListener('message', function (event) { const data = JSON.parse(event.data);

switch(data.type) { case 'chat': displayChatMessage(data.user, data.text); break; case 'system': displaySystemMessage(data.text); break; default: console.log('Tipo de mensagem desconhecido:', data.type); }});

function displayChatMessage(user, text) { const messagesDiv = document.getElementById('messages'); const messageElement = document.createElement('div'); messageElement.innerHTML = `${user}: ${text}`; messagesDiv.appendChild(messageElement);}

function displaySystemMessage(text) { const messagesDiv = document.getElementById('messages'); const messageElement = document.createElement('div'); messageElement.className = 'system-message'; messageElement.textContent = text; messagesDiv.appendChild(messageElement);}


O uso de JSON permite criar protocolos de aplicação flexíveis, onde cada mensagem contém informações sobre seu tipo e dados associados. Isso é especialmente útil para aplicações complexas com diferentes tipos de interações.



Gerenciamento de conexões e escalabilidade



Ao desenvolver aplicações WebSocket reais, é importante considerar o gerenciamento de conexões e a escalabilidade. Aqui estão algumas práticas recomendadas:



  • Heartbeat: Envie mensagens ping/pong periodicamente para verificar se a conexão ainda está ativa e evitar desconexões por inatividade.
  • Salas (Rooms): Agrupe conexões por tópicos ou canais para evitar broadcast desnecessário.
  • Autenticação: Verifique tokens JWT ou cookies durante o handshake WebSocket.
  • Limite de taxa: Implemente rate limiting para evitar sobrecarga do servidor.
  • Balanceamento de carga: Use Redis ou outro mecanismo de pub/sub para sincronizar mensagens entre múltiplas instâncias do servidor.


Exemplo de implementação de heartbeat no servidor:



const WebSocket = require('ws');

const wss = new WebSocket.Server({ port: 8080 });

function heartbeat() { this.isAlive = true;}

wss.on('connection', function connection(ws) { ws.isAlive = true; ws.on('pong', heartbeat);});

// Envia ping para todos os clientes a cada 30 segundosconst interval = setInterval(function ping() { wss.clients.forEach(function each(ws) { if (ws.isAlive === false) { console.log('Cliente desconectado por inatividade'); return ws.terminate(); }

ws.isAlive = false; ws.ping(); });}, 30000);

wss.on('close', function close() { clearInterval(interval);});


Conclusão



WebSocket é uma ferramenta poderosa para criar aplicações web interativas e em tempo real. Combinado com Node.js, ele oferece alto desempenho, facilidade de uso e excelente escalabilidade. Neste artigo, cobrimos os fundamentos: desde a criação de um servidor simples até o gerenciamento de conexões e troca de dados estruturados.



Para projetos reais, recomenda-se usar bibliotecas como Socket.IO, que fornece fallback para tecnologias mais antigas (long polling) e uma API mais conveniente. No entanto, entender o WebSocket puro é essencial para depuração e otimização de aplicações de alto desempenho.



Comece experimentando com exemplos simples, adicione gradualmente funcionalidades como autenticação e salas, e você terá uma base sólida para construir qualquer aplicação em tempo real.

Blogs

Book Recommendations