Como criar um servidor de WebSockets em Node.js

Node.js

Como criar um servidor de WebSockets em Node.js

Luiz Duarte
Escrito por Luiz Duarte em 19/07/2021
Junte-se a mais de 22 mil profissionais de TI

Entre para minha lista e receba conteúdos exclusivos e com prioridade

Em aplicações cliente-servidor tradicionais, o cliente envia requests para o servidor, que por sua vez responde de maneira síncrona. Mas e quando queremos que o servidor envie mensagens para o cliente, como fazer? Por exemplo, após o processamento de uma tarefa demorada, complexa, que não conseguiríamos responder diretamente a um request…Algumas empresas tem a brilhante ideia de fazer polling, que nada mais é do que ficar fazendo requests de tempos em tempos para ver se o servidor tem alguma novidade, uma técnica que até funciona, mas que ao mesmo tempo é extremamente ineficiente.

WebSocket é uma tecnologia que permite comunicação bi-lateral usando uma única conexão (socket) entre o cliente e o servidor. Assim, tanto o cliente pode enviar requests, quando o server, a hora que quiserem após a conexão ser estabelecida. Suportado em todos os browsers modernos, permite criarmos qualquer tipo de troca de informação assíncrona e leve, o que é ideal para aplicações real-time e front-ends reativos (as famosas SPAs ou Single Page Applications).

Em um tutorial aqui do blog, ensino a usar a biblioteca Socket.io para construção de uma aplicação de chat baseada em websockets, inclusive com um cliente para Android. No tutorial de hoje, eu vou ensinar como você pode construir um servidor de websockets em Node.js usando a biblioteca WS, a mais popular e leve, para servir dados assíncronos em real-time para seus clientes.

Veremos neste tutorial:

  1. Setup do Projeto
  2. Setup do servidor de WebSockets
  3. Testando o Websocket Server

Vamos lá!

Livro Node.js

#1 – Setup do Projeto

Crie uma nova pasta chamada server e dentro dela rode o comando abaixo para iniciar uma nova aplicação Node.js zerada.

Instale neste projeto as seguintes dependências: WS, DotEnv, CORS, Morgan, Helmet e Express. O Express é opcional para construção de um servidor websocket, mas como é um web-framework muito popular, vou usá-lo nos exemplos também. Sem Express você pode subir o seu websocket server em um server HTTP comum do Node.js. Junto do Express, decidi por instalar algumas dependências a mais que explico mais tarde, mas que também são opcionais.

Agora crie nesta pasta três arquivos:

  • index.js: responsável por subir nosso servidor;
  • app.js: arquivo de configuração da aplicação Express;
  • app-ws.js: arquivo de configuração do servidor de WebSockets;
  • .env: arquivo de variáveis de ambiente

No arquivo .env, você definirá as variáveis de ambiente da sua aplicação, ou seja, as configurações mais gerais, geralmente relacionadas à infraestrutura e segurança. Em um primeiro momento, vamos precisar de apenas uma configuração: PORT, que é a porta de rede onde nosso servidor estará escutando requisições vindas dos clientes. Caso tenha instalado o pacote CORS, adicione uma configuração para ele também.

Usarei aqui a porta 3000, que é muito popular para aplicações Node.js em geral, mas funciona em qualquer porta que você definir e estiver disponível. Para o CORS, coloquei * a título de exemplo, mas aqui você deve colocar o endereço HTTP do front-end que estará autorizado a acessar o seu servidor, como uma de várias medidas de segurança que você pode definir. Asterisco é a mesma coisa que nada.

Como mencionei antes, o Express é opcional. No entanto, ele permite que você tenha funcionalidades bem interessantes no seu servidor de websockets como por exemplo uma rota de login antes de um socket ser estabelecido. Abaixo, o meu app.js de exemplo com o Morgan configurado para logs de acesso junto do CORS e do Helmet, para segurança básica de servidor.

Repare que nossa rota de login sempre devolve um token, já que implementar alguma mecanismo de autenticação está fora do escopo deste tutorial. Se quiser aprender a implementar um profissional, recomendo ler o tutorial de JSON Web Token.

Agora vamos no nosso arquivo index.js e vamos apenas subir o nosso server Express nele, nada de websockets por enquanto.

Com isso, agora temos o bastante para subir um servidor web que recebe requisições POST em uma rota de login no endereço localhost:3000.

Vamos só ajustar nosso package.json para que incluir um script de inicialização que carrega as variáveis de ambiente e executa nosso index.js

Agora basta executar a aplicação no terminal (primeiro navegue até a pasta do projeto) e testar nossa rota de login usando Postman ou Insomnia.

O setup inicial do nosso projeto está completo!

Curso FullStack

#2 – Setup do servidor de WebSockets

Agora que temos um servidor web up, vamos criar nosso módulo de websockets para que ele possa receber conexões deste tipo, ao invés de requisições HTTP comuns, e a partir daí iniciar a comunicação full-duplex (bi-lateral).

Pegue o seu arquivo app-ws.js para criarmos a primeira versão do nosso servidor, que explicarei a seguir.

Começamos este módulo carregando a dependência do pacote WS e definimos uma série de funções que só fazem mais sentido ao final do módulo onde exportamos uma função que receberá um servidor HTTP por parâmetro, usando o Princípio de Inversão de Dependência (DIP) do SOLID. Não precisa obrigatoriamente ser feito assim, mas é uma boa prática de arquitetura.

Esta função que estamos exportando serve para configurar e retornar o nosso objeto wss (web socket server). Começamos a configuração através da classe WebSocket.Server passando o servidor HTTP recebido por parâmetro. Depois, adicionamos um handler/listener/callback (como quiser chamar) do evento connection que será disparado toda vez que uma nova conexão for efetuada com sucesso em nosso servidor de websockets.

Se você olhar mais acima, verá o que faz essa função: ela recebe o websocket (a conexão cliente-servidor) e a request HTTP original. Com este objeto websocket (ws), podemos configurar então os callbacks para os eventos de message e error.

O evento de message será disparado toda vez que o servidor receber uma mensagem do cliente. Assim, nesta function onMessage, que recebe uma string data por parâmetro, você tratará o recebimento de requests (sempre string) dos clientes de websocket. O objeto ws recebido por parâmetro é a conexão do cliente com seu servidor e pode utilizá-la para enviar mensagens de volta para ele.

O evento de error será disparado toda vez que o servidor tiver uma falha inesperada. Assim, nesta função onError, que recebe um objeto de erro você tratará as falhas do servidor e através do objeto ws recebido por parâmetro, consegue receber quem é o cliente que ocasionou o erro.

Agora, vamos plugar este app-ws.js em nosso app.js através de configurações no index.js.

Repare como peguei o retorno do listen do app Express, que nada mais é do que um server HTTP e passei para a função exportada do app-ws. Com isso, ao rodarmos agora nossa aplicação novamente com npm start, não apenas teremos subido um server HTTP mas também um server WS, na mesma porta. Conforme o protocolo utilizado na requisição, HTTP ou WS, a aplicação específica será chamada.

Mas como eu testo um servidor de websockets sem ter uma cliente construído?

Curso Node.js e MongoDB

#3 – Testando o WebSocket Server

Para fazer os testes do websocket server precisamos de um cliente de websockets. Podemos criar um com algum pacote como Socket.io ou podemos, no mesmo estilo do Postman, usar um client gráfico como o Smart WebSocket Client, disponível para download gratuito como extensão do Google Chrome neste link. Basta instalar ele como extensão e deixá-lo ativo no navegador.

Certifique-se de estar com seu servidor de websockets rodando e configure o endereço do Smart WS Client para ws://localhost:3000, que é o endereço do nosso servidor. Clique em Connect e se tudo deu certo, ele deve avisar “everything is ok”, bem como se você olhar o terminal onde está rodando o servidor, verá uma mensagem no console de que ele passou pela função onConnection.

Agora, você pode usar a caixa de texto e o botão sendo do Smart WS Client para enviar mensagens para o seu servidor. Como não implementamos nenhuma lógica específica nele, você apenas verá no terminal do backend as mensagens chegando, indicando que o servidor as está recebendo, bem como receberá uma mensagem “recebido” como retorno no seu cliente.

Em um cenário real, provavelmente você irá querer trabalhar com JSON ao invés de mensagens de texto plano, e também armazenar no servidor quem é quem dentre todos os clientes conectados. Mas a lógica sempre será essa aí que acabei de mostrar.

Além disso, repare que usei o protocolo ws:// no início do endereço. WebSockets que estejam rodando em canal HTTPS devem usar o protocolo wss:// para funcionar.

E por fim, na próxima lição vamos aprender a enviar mensagens do servidor para os clientes, bem como iremos adicionar segurança em nosso websockets server, para que somente usuários autenticados possam se conectar nele. Você confere a parte 2 clicando neste link.

 

TAGS: nodejs

Olá, tudo bem?

O que você achou deste conteúdo? Conte nos comentários.