Node.js HTTP Client Tunnel Proxy: axios / got / http Comparison

Three Node.js HTTP clients (axios + https-proxy-agent, got, native http) implementing four tunnel proxy scenarios with 16Yun Crawler Proxy.

16Yun Engineering TeamJun 1, 20261 min read

Node.js Proxy Ecosystem

Node.js HTTP clients use http-proxy-agent / https-proxy-agent for proxy support. https-proxy-agent supports custom headers at the CONNECT stage for Proxy-Tunnel.

Setup

export PROXY_HOST=t.16yun.cn
export PROXY_PORT=31111
export PROXY_USERNAME=your-username
export PROXY_PASSWORD=your-password
export PROXY_TUNNEL=nodejs-demo-12345

axios + https-proxy-agent

const axios = require('axios');
const { HttpsProxyAgent } = require('https-proxy-agent');

const proxyUrl = `http://${user}:${pass}@${host}:${port}`;
const tunnelVal = process.env.PROXY_TUNNEL || 'axios-demo';

// Scenario C-HTTPS: Proxy-Tunnel via agent options
const agent = new HttpsProxyAgent(proxyUrl, {
  headers: { 'Proxy-Tunnel': tunnelVal }, // Sent during CONNECT
});

async function main() {
  for (let i = 1; i <= 3; i++) {
    const resp = await axios.get('https://httpbin.org/ip', { httpsAgent: agent });
    console.log(`Request ${i}: ${resp.data.origin}`);
  }
}
main();

All Four Scenarios

// A: Force new — new agent each request
const agent = new HttpsProxyAgent(proxyUrl);
await axios.get(url, { httpsAgent: agent, headers: { 'Connection': 'close' } });

// B: Keep-Alive — reuse agent
const agentK = new HttpsProxyAgent(proxyUrl);
for (let i = 0; i < 3; i++) {
  await axios.get(url, { httpsAgent: agentK, headers: { 'Connection': 'keep-alive' } });
}

// C-HTTP: Proxy-Tunnel on request
await axios.get('http://httpbin.org/ip', {
  httpAgent: new HttpProxyAgent(proxyUrl),
  headers: { 'Proxy-Tunnel': tunnelVal },
});

// C-HTTPS: Proxy-Tunnel via agent options
const tunnelAgent = new HttpsProxyAgent(proxyUrl, {
  headers: { 'Proxy-Tunnel': tunnelVal },
});
await axios.get('https://httpbin.org/ip', { httpsAgent: tunnelAgent });

got

const got = require('got');
const { HttpsProxyAgent } = require('https-proxy-agent');

const agent = {
  https: new HttpsProxyAgent(proxyUrl, {
    headers: { 'Proxy-Tunnel': process.env.PROXY_TUNNEL || 'got-demo' },
  }),
};

const resp = await got('https://httpbin.org/ip', { agent });
console.log(JSON.parse(resp.body).origin);

Native http Module

HTTP targets only — native module can't handle HTTPS CONNECT natively:

const http = require('http');
const auth = Buffer.from(`${user}:${pass}`).toString('base64');

const options = {
  hostname: host, port: parseInt(port), method: 'GET',
  path: 'http://httpbin.org/ip',
  headers: {
    'Host': 'httpbin.org',
    'Proxy-Authorization': `Basic ${auth}`,
    'Proxy-Tunnel': process.env.PROXY_TUNNEL || 'http-demo',
  },
};

const req = http.request(options, (res) => {
  res.setEncoding('utf8');
  res.on('data', (chunk) => process.stdout.write(chunk));
});
req.end();

Comparison

Aspectaxios + agentgotNative http
HTTPS❌ Needs agent
HTTPS Tunnelheaders option✅ agent config
APIModerateCleanVerbose
EcosystemLargestGrowingNo deps
curl -x http://$PROXY_USERNAME:$PROXY_PASSWORD@$PROXY_HOST:$PROXY_PORT https://httpbin.org/ip

Need an enterprise proxy plan?

We can tailor architecture to your target domains, concurrency, and reliability goals.