API WebSocket do JavaScript
Aprenda a API WebSocket do JavaScript: ciclo de vida da conexão, readyState, envio de texto, JSON e dados binários, reconexão e segurança, com exemplo de Echo Chat executável.
Introdução à Tecnologia WebSocket
WebSocket é um protocolo que fornece um canal de comunicação full-duplex (bidirecional) entre o navegador e um servidor por meio de uma única conexão TCP de longa duração. Uma vez que a conexão está aberta, qualquer lado pode enviar uma mensagem a qualquer momento sem esperar que o outro solicite — algo que o HTTP comum não consegue fazer.
Esta página aborda o que os WebSockets resolvem, o ciclo de vida da conexão, o envio de dados de texto e binários, o trabalho com mensagens JSON, reconexão, segurança e quando usar uma biblioteca em vez da API bruta. Construímos tudo em torno de um exemplo de Echo Chat executável.
Por que WebSockets em vez de HTTP?
Com o HTTP comum (incluindo a Fetch API e o XMLHttpRequest), o cliente deve iniciar cada troca. Para obter atualizações em tempo real, você precisa usar polling — perguntar repetidamente "há algo novo?" — o que desperdiça largura de banda e aumenta a latência. Os WebSockets invertem isso: o servidor pode enviar dados no instante em que tiver algo, com quase nenhuma sobrecarga por mensagem.
| Abordagem | Direção | Sobrecarga | Melhor para |
|---|---|---|---|
| Requisição/resposta HTTP | O cliente pergunta, o servidor responde | Cabeçalhos completos por requisição | Buscas únicas, REST APIs |
| Polling | O cliente pergunta em intervalos | Muitas requisições desnecessárias | Atualizações simples e de baixa frequência |
| WebSocket | Ambos enviam livremente | Um handshake, frames pequenos | Chat, feeds ao vivo, jogos, dashboards |
Use WebSockets quando o servidor precisar falar primeiro ou quando as mensagens fluírem constantemente: chat, jogos multiplayer, editores colaborativos, tickers de negociação e dashboards ao vivo. Para atualizações ocasionais e unidirecionais do servidor para o cliente apenas, Server-Sent Events ou a Push API podem ser mais simples.
O Ciclo de Vida da Conexão WebSocket
Você abre uma conexão passando uma URL ws:// (simples) ou wss:// (criptografada) para o construtor WebSocket. A conexão então passa por quatro estados expostos por socket.readyState:
| Constante | Valor | Significado |
|---|---|---|
WebSocket.CONNECTING | 0 | Handshake em andamento (estado inicial) |
WebSocket.OPEN | 1 | Pronto para enviar e receber |
WebSocket.CLOSING | 2 | Um fechamento foi solicitado |
WebSocket.CLOSED | 3 | Conexão fechada ou falhou ao abrir |
Você reage às transições com quatro eventos: open, message, error e close. A regra principal é que você só pode chamar socket.send() enquanto readyState for OPEN — enviar antes que open seja disparado gera um erro.
const socket = new WebSocket("wss://echo.websocket.events");
socket.addEventListener("open", () => {
console.log("open, readyState =", socket.readyState); // 1
socket.send("hello");
});
socket.addEventListener("message", (event) => {
console.log("received:", event.data); // "hello" (echoed back)
});
socket.addEventListener("close", (event) => {
console.log("closed, code =", event.code); // e.g. 1000
});Configurando o Echo Chat WebSocket
Estrutura HTML Básica
Primeiro, estabelecemos a interface do usuário com HTML que inclui uma área de exibição de mensagens, campo de entrada e botões de controle.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebSocket Echo Chat</title>
</head>
<body>
<textarea id="chatBox" readonly style="width: 100%; height: 300px"></textarea><br />
<input type="text" id="messageInput" placeholder="Type a message..." style="width: 75%" />
<button onclick="sendMessage()">Send</button>
<button onclick="closeConnection()">Close Connection</button>
</body>
</html>Integrando WebSocket com JavaScript
O JavaScript para gerenciar a comunicação WebSocket é fundamental para habilitar interações em tempo real.
<script>
// Accessing the chat box and message input elements from the HTML.
const chatBox = document.getElementById("chatBox");
const messageInput = document.getElementById("messageInput");
// Establishing a WebSocket connection to the echo server.
const socket = new WebSocket("wss://echo.websocket.events");
// When the connection is open, display a connected message in the chat box.
socket.addEventListener("open", function (event) {
chatBox.value += "Connected to the echo server\n";
});
// Handle incoming messages by adding them to the chat box.
socket.addEventListener("message", function (event) {
chatBox.value += "Echoed back: " + event.data + "\n";
});
// Handle connection errors.
socket.addEventListener("error", function (event) {
chatBox.value += "Connection error occurred.\n";
});
// Handle connection closure.
socket.addEventListener("close", function (event) {
chatBox.value += "Connection closed. Code: " + event.code + "\n";
});
// Function to send a message when the send button is clicked.
function sendMessage() {
const message = messageInput.value; // Get the message from the input field.
if (!message) return; // If there's no message, don't do anything.
socket.send(message); // Send the message to the server.
chatBox.value += "You: " + message + "\n"; // Show the message in the chat box.
messageInput.value = ""; // Clear the message input field.
}
// Function to close the WebSocket connection.
function closeConnection() {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The user closed the connection"); // Close the connection normally.
chatBox.value += "Connection closed by user\n"; // Inform the user in the chat box.
} else {
alert("Connection is not open or already closed."); // Alert if the connection can't be closed.
}
}
// Ensure the WebSocket is closed properly when the webpage is closed or reloaded.
window.addEventListener("beforeunload", function () {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The page is unloading"); // Close the connection normally.
}
});
</script>Este script configura um recurso de chat em uma página web que se conecta a um servidor usando WebSockets. Veja uma explicação simples de suas partes:
- Acessando Elementos HTML: O script obtém a caixa de chat e a caixa de entrada de mensagens da página web para poder interagir com elas.
- Conexão WebSocket: Ele abre uma conexão com um servidor que ecoa as mensagens de volta. Isso significa que tudo o que você enviar para este servidor será enviado de volta para você.
- Exibindo o Status da Conexão: Quando a conexão é estabelecida com sucesso, uma mensagem é exibida na caixa de chat informando que a conexão com o servidor de eco foi estabelecida.
- Tratando Mensagens Recebidas: Quaisquer mensagens que retornem do servidor são adicionadas à caixa de chat, mostrando que o servidor ecoou as mensagens.
- Enviando Mensagens: Há uma função para enviar mensagens digitadas na caixa de entrada. Se houver texto, ele o envia para o servidor e depois o exibe na caixa de chat como sua mensagem.
- Fechando a Conexão: Há também uma função para fechar a conexão WebSocket quando necessário, como quando o usuário decide fechá-la ou quando a página web está sendo fechada.
Esta configuração permite comunicação em tempo real com o servidor e ajuda a testar e demonstrar como funcionam os aplicativos de mensagens.
E agora vamos juntar tudo e ver em ação:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WebSocket Echo Chat</title>
</head>
<body>
<textarea id="chatBox" readonly style="width: 100%; height: 300px">
</textarea>
<br />
<input
type="text"
id="messageInput"
placeholder="Type a message..."
style="width: 75%"
/>
<button onclick="sendMessage()">Send</button>
<button onclick="closeConnection()">Close Connection</button>
</body>
<script>
const chatBox = document.getElementById("chatBox");
const messageInput = document.getElementById("messageInput");
const socket = new WebSocket("wss://echo.websocket.events");
socket.addEventListener("open", function (event) {
chatBox.value += "Connected to the echo server\n";
});
socket.addEventListener("message", function (event) {
chatBox.value += "Echoed back: " + event.data + "\n";
});
socket.addEventListener("error", function (event) {
chatBox.value += "Connection error occurred.\n";
});
socket.addEventListener("close", function (event) {
chatBox.value += "Connection closed. Code: " + event.code + "\n";
});
function sendMessage() {
const message = messageInput.value;
if (!message) return;
socket.send(message);
chatBox.value += "You: " + message + "\n";
messageInput.value = "";
}
function closeConnection() {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The user closed the connection");
chatBox.value += "Connection closed by user\n";
} else {
alert("Connection not open or already closed.");
}
}
window.addEventListener("beforeunload", function () {
if (socket.readyState === WebSocket.OPEN) {
socket.close(1000, "The page is unloading");
}
});
</script>
</html>No exemplo acima, assim que você se conecta ao servidor, pode começar a enviar mensagens e receberá exatamente o que digitou, ecoado de volta para você. Se você clicar no botão 'Close Connection', a conexão WebSocket será encerrada e você não receberá mais mensagens ecoadas.
Recursos e Técnicas Avançados de WebSocket
Enviando Dados Estruturados como JSON
Aplicativos reais raramente enviam strings simples — eles enviam objects. Como o canal de transmissão só suporta texto ou binário, você serializa objects com JSON.stringify() antes de enviar e os analisa com JSON.parse() na chegada. Veja Trabalhando com JSON para mais informações sobre este formato.
// Sending an object
const payload = { type: "chat", user: "Ann", text: "Hi!" };
socket.send(JSON.stringify(payload));
// Receiving and parsing it
socket.addEventListener("message", (event) => {
const msg = JSON.parse(event.data);
console.log(msg.user + ": " + msg.text); // "Ann: Hi!"
});Um padrão comum é um campo type que permite que uma conexão multiplexe muitos tipos de mensagens — chat, presence, typing, entre outros — cada um tratado por seu próprio bloco.
Manipulando Dados Binários
WebSockets não se limitam a texto. Eles também podem carregar frames binários, úteis para áudio, imagens ou estado de jogo. Defina socket.binaryType para controlar como os dados binários recebidos chegam — "blob" (o padrão) ou "arraybuffer".
socket.binaryType = "arraybuffer";
// Send raw bytes
const bytes = new Uint8Array([72, 73]); // "HI"
socket.send(bytes);
socket.addEventListener("message", (event) => {
if (typeof event.data === "string") {
console.log("text frame:", event.data);
} else {
const view = new Uint8Array(event.data);
console.log("binary frame, length:", view.length);
}
});Reconexão Automática
Redes caem. O WebSocket bruto não reconecta por conta própria — quando close é disparado inesperadamente, você deve reabrir a conexão manualmente, idealmente com um recuo crescente (exponencial) para não sobrecarregar o servidor.
let delay = 1000; // start at 1 second
function connect() {
const socket = new WebSocket("wss://echo.websocket.events");
socket.addEventListener("open", () => {
delay = 1000; // reset back-off after a successful connection
});
socket.addEventListener("close", () => {
setTimeout(connect, delay);
delay = Math.min(delay * 2, 30000); // cap at 30 seconds
});
}
connect();Implementando Segurança em WebSocket
A segurança é fundamental ao lidar com WebSockets:
- Use WSS: Sempre use WebSocket Secure (WSS), que criptografa os dados transmitidos entre o cliente e o servidor.
- Autenticação: Implemente autenticação baseada em token para garantir que apenas usuários autorizados possam estabelecer conexões WebSocket.
- Validação: Valide adequadamente todos os dados enviados ao servidor para evitar vulnerabilidades web comuns, como XSS ou injeção SQL.
WebSocket e o Padrão Pub/Sub
O padrão publish/subscribe é um modelo popular em serviços de dados em tempo real, onde as mensagens são transmitidas por um canal. Serviços WebSocket como PubNub oferecem APIs que suportam o modelo pub/sub, aprimorando as capacidades do WebSocket ao gerenciar conexões, fornecer criptografia de dados e facilitar transmissões baseadas em canais.
Bibliotecas e Frameworks WebSocket
Várias bibliotecas JavaScript tornam o trabalho com WebSockets mais fácil e robusto:
- Socket.IO: Fornece recursos adicionais como reconexão automática, tratamento de eventos e gerenciamento de salas.
- WebSocket-Node: Uma implementação de servidor WebSocket para Node.js.
- ReconnectingWebSocket: Uma pequena biblioteca que adiciona recursos de reconexão a WebSockets simples.
Conclusão
A tecnologia WebSocket é um bloco de construção fundamental para o desenvolvimento de aplicativos web interativos e em tempo real. Ao integrar WebSockets em seus aplicativos, você habilita a interação direta e bidirecional entre clientes e servidores. Este guia percorreu o ciclo de vida da conexão, o exemplo de Echo Chat, mensagens JSON e binárias, reconexão e segurança — o suficiente para construir recursos em tempo real robustos.
Veja Também
- Fetch API — para requisições HTTP únicas quando você não precisa de um canal ativo.
- XMLHttpRequest — a API de requisição mais antiga sobre a qual WebSockets e Fetch se baseiam conceitualmente.
- Push API — mensagens do servidor para o cliente mesmo quando a página está fechada.
- Trabalhando com JSON — o formato padrão para mensagens WebSocket estruturadas.