Cliente HTTP em JavaScript: técnicas avançadas de requisições em 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

Cliente HTTP em JavaScript: fazendo requisições corretamente — nível avançado



Requisições HTTP básicas com fetch ou axios são apenas a ponta do iceberg. Em aplicações reais de produção em Node.js, você encontra dezenas de nuances: pools de conexão, tentativas repetidas em falhas, interceptadores para logging, streaming de grandes dados e ajuste fino de timeouts. Neste artigo, abordaremos técnicas avançadas de trabalho com clientes HTTP em JavaScript. Você aprenderá como gerenciar keep-alive, implementar um mecanismo retry confiável, usar interceptadores e criar agentes personalizados. O material é voltado para desenvolvedores que já conhecem os fundamentos do HTTP e desejam escrever código mais eficiente e tolerante a falhas.



1. Gerenciamento de conexões: Keep-Alive e agentes personalizados



Por padrão, o Node.js usa um pool global de agentes HTTP. No entanto, para sistemas de alta carga, é importante controlar o número de conexões simultâneas e seu reuso. Vamos analisar a configuração de keep-alive usando o módulo http e a biblioteca undici.



Exemplo com agente personalizado (Node.js built-in):

const http = require('http');const https = require('https');

// Criando um agente personalizado com pool de conexõesconst agent = new http.Agent({ keepAlive: true, maxSockets: 50, // Máximo de 50 sockets simultâneos maxFreeSockets: 10, // No máximo 10 sockets livres no pool timeout: 60000, // Timeout de inatividade do socket (ms)});

const options = { hostname: 'api.example.com', port: 80, path: '/data', agent: agent,};

const req = http.get(options, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => console.log('Resposta recebida:', data));});

req.on('error', (e) => console.error('Erro:', e.message));


Abordagem moderna com undici (mais rápida e leve):

const { Client, Pool } = require('undici');

// Criando um pool com keep-aliveconst client = new Pool('https://api.example.com', { connections: 100, pipelining: 10, keepAliveTimeout: 30000,});

// Executando a requisiçãoclient.request({ method: 'GET', path: '/data',}).then(({ statusCode, body }) => { console.log('Status:', statusCode); body.setEncoding('utf8'); body.on('data', console.log);}).catch(err => console.error(err));


O uso de agentes personalizados evita problemas com vazamento de sockets e melhora o desempenho através do reuso de conexões.



2. Mecanismo confiável de tentativas repetidas (Retry)



Redes são instáveis. Mesmo falhas temporárias podem levar à perda de dados. Uma estratégia de retry adequada deve considerar o tipo de erro, o número de tentativas e um atraso exponencial. Vamos implementar um decorador retry universal para qualquer cliente HTTP.



const axios = require('axios');const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));

async function withRetry(requestFn, retries = 3, baseDelay = 1000) { for (let attempt = 1; attempt <= retries; attempt++) { try { return await requestFn(); } catch (error) { // Não repetir em erros do cliente (4xx) if (error.response && error.response.status >= 400 && error.response.status < 500) { throw error; } if (attempt === retries) { throw error; // Todas as tentativas esgotadas } const delay = baseDelay * Math.pow(2, attempt - 1) + Math.random() * 1000; console.log(`Tentativa ${attempt} falhou. Aguardando ${delay}ms...`); await sleep(delay); } }}

// Usoasync function fetchData() { const response = await withRetry(() => axios.get('https://api.example.com/data'), 5, 500); return response.data;}

fetchData().then(console.log).catch(console.error);


Pontos-chave: exclusão de erros 4xx-

Blogs

Book Recommendations