Skip to content

Repository files navigation

npm version

JavaScript Proxy Headers

Extensions for JavaScript HTTP libraries to support sending and receiving custom proxy headers during HTTPS CONNECT tunneling.

The Problem

When making HTTPS requests through a proxy, the connection is established via a CONNECT tunnel. During this process:

  1. Sending headers to the proxy - Most JavaScript HTTP libraries don't provide a way to send custom headers (like X-ProxyMesh-Country) to the proxy server during the CONNECT handshake.

  2. Receiving headers from the proxy - The proxy's response headers from the CONNECT request are typically discarded, making it impossible to read custom headers (like X-ProxyMesh-IP) that the proxy sends back.

This library solves both problems for popular JavaScript HTTP libraries.

Supported Libraries

LibrarySubpath exportNotes
axiosjavascript-proxy-headers/axiosWidely used client
node-fetchjavascript-proxy-headers/node-fetchFetch API on Node
gotjavascript-proxy-headers/gotErgonomic API
undicijavascript-proxy-headers/undiciNode’s fast HTTP stack
superagentjavascript-proxy-headers/superagentChaining API
kyjavascript-proxy-headers/kyTiny fetch wrapper
wretchjavascript-proxy-headers/wretchFetch wrapper (sets wretch’s global fetch polyfill)
make-fetch-happenjavascript-proxy-headers/make-fetch-happennpm-style fetch (cache, retries, proxy)
needlejavascript-proxy-headers/needleLean HTTP client
typed-rest-clientjavascript-proxy-headers/typed-rest-clientAzure / DevOps–style REST client

urllib is not integrated yet: it expects an undiciDispatcher, not a Node Agent. See notes/urllib-integration-deferred.md in this repo for a possible approach.

Installation

npm install javascript-proxy-headers

Then install the HTTP client(s) you use (for example axios, got, ky, wretch, make-fetch-happen, needle, or typed-rest-client). Each is an optional peer dependency.

Note: This package has no runtime dependencies by default—install only the adapters you need.

Quick Start

axios

import{createProxyAxios}from'javascript-proxy-headers/axios';constclient=createProxyAxios({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitclient.get('https://httpbin.org/ip');// Proxy headers are merged into response.headersconsole.log(response.headers['x-proxymesh-ip']);

node-fetch

import{proxyFetch}from'javascript-proxy-headers/node-fetch';constresponse=awaitproxyFetch('https://httpbin.org/ip',{proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});// Proxy headers available on responseconsole.log(response.proxyHeaders.get('x-proxymesh-ip'));

got

import{createProxyGot}from'javascript-proxy-headers/got';constclient=createProxyGot({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitclient('https://httpbin.org/ip');console.log(response.headers['x-proxymesh-ip']);

undici

import{request}from'javascript-proxy-headers/undici';const{ statusCode, headers, body, proxyHeaders }=awaitrequest('https://httpbin.org/ip',{proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});console.log(proxyHeaders.get('x-proxymesh-ip'));

ky

Uses a custom fetch built from node-fetch + ProxyHeadersAgent (ky.create({ fetch })).

import{createProxyKy}from'javascript-proxy-headers/ky';constapi=awaitcreateProxyKy({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitapi('https://httpbin.org/ip');console.log(response.proxyHeaders.get('x-proxymesh-ip'));

wretch

Registers the same custom fetch as wretch’s fetch polyfill. Use the normal wretch chain (for example .get().res()).

import{createProxyWretch}from'javascript-proxy-headers/wretch';constwretch=awaitcreateProxyWretch({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitwretch('https://httpbin.org/ip').get().res();console.log(response.proxyHeaders.get('x-proxymesh-ip'));

make-fetch-happen

Passes a ProxyHeadersAgent as agent; @npmcli/agent uses it as-is when set.

import{createProxyMakeFetchHappen}from'javascript-proxy-headers/make-fetch-happen';constfetch=createProxyMakeFetchHappen({proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});constresponse=awaitfetch('https://httpbin.org/ip');console.log(response.proxyHeaders.get('x-proxymesh-ip'));

needle

import{proxyNeedleGet}from'javascript-proxy-headers/needle';constres=awaitproxyNeedleGet('https://httpbin.org/ip',{proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});// CONNECT response headers merged onto res.headers where missingconsole.log(res.headers['x-proxymesh-ip']);

typed-rest-client

Uses a subclass of HttpClient that routes HTTPS through ProxyHeadersAgent (no tunnel agent).

import{createProxyRestClient}from'javascript-proxy-headers/typed-rest-client';constclient=createProxyRestClient({userAgent: 'my-app',proxy: 'http://user:pass@proxy.example.com:8080',proxyHeaders: {'X-ProxyMesh-Country': 'US'}});awaitclient.get('https://httpbin.org/ip');console.log(client.proxyAgent.lastProxyHeaders?.get('x-proxymesh-ip'));

Core Agent (Advanced)

For direct control, use the core ProxyHeadersAgent:

import{ProxyHeadersAgent}from'javascript-proxy-headers';importhttpsfrom'https';constagent=newProxyHeadersAgent('http://proxy.example.com:8080',{proxyHeaders: {'X-ProxyMesh-Country': 'US'},onProxyConnect: (headers)=>{console.log('Proxy IP:',headers.get('x-proxymesh-ip'));}});https.get('https://httpbin.org/ip',{ agent },(res)=>{// Handle response});

Testing

Integration tests need a real proxy (set PROXY_URL or HTTPS_PROXY):

export PROXY_URL='http://user:pass@proxy.example.com:8080'
npm test# all adapters (see package.json "test")
node run_tests.js -v # same harness from repo root
npm run test:ts # same checks via tsx + TypeScript harness
npm run test:types # `tsc --noEmit` only (no network)# Limit modules
node test/test_proxy_headers.js -v axios ky

Verbose (-v) prints captured header values. See test/test_proxy_headers.js --help.

Requirements

  • Node.js >= 18.0.0
  • One or more supported HTTP libraries

Related Projects

About

Created by ProxyMesh to help our customers use custom headers to control proxy behavior. Works with any proxy that supports custom headers.

License

MIT License

About

Extensions for JavaScript HTTP libraries to support custom proxy headers during HTTPS CONNECT tunneling

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages