Skip to content

Commit 8179250

Browse files
author
Cursor
committed
Merge main into feature/php-examples and resolve README conflicts.
Keep the updated Ruby docs from main, retain the PHP section, and normalize PHP PROXY_URL handling so host-only values like us-ca.proxymesh.com are testable across all PHP examples and the PHP test runner. Made-with: Cursor
2 parents 79923cd + 397d2e5 commit 8179250

40 files changed

Lines changed: 4819 additions & 70 deletions

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,10 @@ dmypy.json
127127

128128
# Pyre type checker
129129
.pyre/
130+
131+
# Node.js (JavaScript examples)
132+
javascript/node_modules/
133+
134+
# Ruby (Bundler)
135+
ruby/vendor/bundle/
136+
ruby/.bundle/

README.md

Lines changed: 145 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Example code for using proxy servers in different programming languages. Currently we have examples for these languages:
44

55
* Python
6+
* JavaScript / Node.js
67
* Ruby
78
* PHP
89

@@ -51,16 +52,18 @@ python python/run_tests.py requests-proxy-headers httpx-proxy-headers
5152
| Library | Example | Description |
5253
|---------|---------|-------------|
5354
| [requests](https://docs.python-requests.org/) | [requests-proxy-headers.py](python/requests-proxy-headers.py) | Simple HTTP requests with proxy headers |
54-
| requests | [requests-proxy-headers-session.py](python/requests-proxy-headers-session.py) | Session-based requests for connection pooling |
55+
| [requests](https://docs.python-requests.org/) | [requests-proxy-headers-session.py](python/requests-proxy-headers-session.py) | Session-based requests for connection pooling |
5556
| [urllib3](https://urllib3.readthedocs.io/) | [urllib3-proxy-headers.py](python/urllib3-proxy-headers.py) | Low-level HTTP client with proxy headers |
5657
| [aiohttp](https://docs.aiohttp.org/) | [aiohttp-proxy-headers.py](python/aiohttp-proxy-headers.py) | Async HTTP client with proxy headers |
5758
| [httpx](https://www.python-httpx.org/) | [httpx-proxy-headers.py](python/httpx-proxy-headers.py) | Modern HTTP client with proxy headers |
58-
| httpx | [httpx-async-proxy-headers.py](python/httpx-async-proxy-headers.py) | Async httpx with proxy headers |
59+
| [httpx](https://www.python-httpx.org/) | [httpx-async-proxy-headers.py](python/httpx-async-proxy-headers.py) | Async httpx with proxy headers |
5960
| [pycurl](http://pycurl.io/) | [pycurl-proxy-headers.py](python/pycurl-proxy-headers.py) | libcurl bindings with proxy headers |
60-
| pycurl | [pycurl-proxy-headers-lowlevel.py](python/pycurl-proxy-headers-lowlevel.py) | Low-level pycurl integration |
61+
| [pycurl](http://pycurl.io/) | [pycurl-proxy-headers-lowlevel.py](python/pycurl-proxy-headers-lowlevel.py) | Low-level pycurl integration |
6162
| [cloudscraper](https://github.com/venomous/cloudscraper) | [cloudscraper-proxy-headers.py](python/cloudscraper-proxy-headers.py) | Cloudflare bypass with proxy headers |
6263
| [autoscraper](https://github.com/alirezamika/autoscraper) | [autoscraper-proxy-headers.py](python/autoscraper-proxy-headers.py) | Automatic web scraping with proxy headers |
6364

65+
> **Note:** Most Python HTTP libraries do not expose custom headers on HTTPS `CONNECT` tunneling by default. These examples use [python-proxy-headers](https://github.com/proxymesh/python-proxy-headers) adapters to send proxy headers and read proxy response headers consistently.
66+
6467
### Basic Proxy Examples
6568

6669
* [requests-proxy.py](python/requests-proxy.py) - Basic proxy usage with requests
@@ -70,13 +73,13 @@ python python/run_tests.py requests-proxy-headers httpx-proxy-headers
7073

7174
* [scrapy-proxy-headers.py](python/scrapy-proxy-headers.py) - Scrapy spider with proxy headers
7275

73-
## Ruby Proxy Examples
76+
## JavaScript / Node.js Proxy Examples
7477

7578
**Installation:**
7679

7780
```bash
78-
cd ruby
79-
bundle install
81+
cd javascript
82+
npm install
8083
```
8184

8285
**Running Examples:**
@@ -86,27 +89,82 @@ bundle install
8689
export PROXY_URL='http://user:pass@proxy.example.com:8080'
8790

8891
# Run a single example
89-
ruby ruby/faraday_proxy.rb
92+
node javascript/axios-proxy.js
9093

9194
# Run all examples as tests
92-
ruby ruby/run_tests.rb
95+
node javascript/run_tests.js
96+
97+
# Run specific examples
98+
node javascript/run_tests.js axios got
99+
```
100+
101+
**Examples:**
102+
103+
| Library | Example | Description |
104+
|---------|---------|-------------|
105+
| [axios](https://axios-http.com/) | [axios-proxy.js](javascript/axios-proxy.js) | Popular promise-based HTTP client |
106+
| [node-fetch](https://github.com/node-fetch/node-fetch) | [node-fetch-proxy.js](javascript/node-fetch-proxy.js) | Fetch API for Node.js |
107+
| [got](https://github.com/sindresorhus/got) | [got-proxy.js](javascript/got-proxy.js) | Human-friendly HTTP client |
108+
| [undici](https://undici.nodejs.org/) | [undici-proxy.js](javascript/undici-proxy.js) | Fast HTTP client (powers Node.js fetch) |
109+
| [superagent](https://github.com/ladjs/superagent) | [superagent-proxy.js](javascript/superagent-proxy.js) | Flexible HTTP client |
110+
| [needle](https://github.com/tomas/needle) | [needle-proxy.js](javascript/needle-proxy.js) | Lean HTTP client |
111+
| [puppeteer](https://pptr.dev/) | [puppeteer-proxy.js](javascript/puppeteer-proxy.js) | Headless Chrome automation |
112+
| [playwright](https://playwright.dev/) | [playwright-proxy.js](javascript/playwright-proxy.js) | Browser automation |
113+
| [cheerio](https://cheerio.js.org/) | [cheerio-proxy.js](javascript/cheerio-proxy.js) | HTML parsing with node-fetch |
114+
| [ky](https://github.com/sindresorhus/ky) | [ky-proxy.js](javascript/ky-proxy.js) | Fetch wrapper (node-fetch + agent) |
115+
| [wretch](https://github.com/elbywan/wretch) | [wretch-proxy.js](javascript/wretch-proxy.js) | Fetch wrapper (polyfill) |
116+
| [make-fetch-happen](https://github.com/npm/make-fetch-happen) | [make-fetch-happen-proxy.js](javascript/make-fetch-happen-proxy.js) | npm-style fetch |
117+
| [typed-rest-client](https://github.com/microsoft/typed-rest-client) | [typed-rest-client-proxy.js](javascript/typed-rest-client-proxy.js) | REST client (built-in proxy option) |
118+
119+
> **Note:** None of these libraries currently support sending custom headers to the proxy during HTTPS CONNECT tunneling or reading proxy response headers. See [javascript-proxy-headers](https://github.com/proxymesh/javascript-proxy-headers) for extension modules that add this capability.
120+
121+
## Ruby Proxy Examples
122+
123+
These examples use [Bundler](https://bundler.io/). Install Ruby development headers and libcurl first so native extensions can compile (Debian/Ubuntu: `ruby-dev` and `libcurl4-openssl-dev`; Fedora: `ruby-devel` and `libcurl-devel`).
124+
125+
```bash
126+
cd ruby
127+
bundle install
128+
```
129+
130+
**Running examples:**
131+
132+
```bash
133+
# Required: set your proxy URL
134+
export PROXY_URL='http://user:pass@proxy.example.com:8080'
135+
136+
# Optional: target URL (default: https://api.ipify.org?format=json)
137+
export TEST_URL='https://httpbin.org/ip'
138+
139+
# Optional: print one response header
140+
export RESPONSE_HEADER='X-ProxyMesh-IP'
141+
142+
# Single example (from ruby/)
143+
bundle exec ruby faraday-proxy.rb
144+
145+
# All examples as tests
146+
bundle exec ruby run_tests.rb
147+
148+
# Specific examples
149+
bundle exec ruby run_tests.rb faraday typhoeus
93150
```
94151

95152
**Examples:**
96153

97154
| Library | Example | Description |
98155
|---------|---------|-------------|
99-
| [Net::HTTP](https://ruby-doc.org/stdlib/libdoc/net/http/rdoc/Net/HTTP.html) | [net_http_proxy.rb](ruby/net_http_proxy.rb) | Ruby standard library HTTP client |
100-
| [Faraday](https://lostisland.github.io/faraday/) | [faraday_proxy.rb](ruby/faraday_proxy.rb) | HTTP client with middleware support |
101-
| [HTTParty](https://github.com/jnunemaker/httparty) | [httparty_proxy.rb](ruby/httparty_proxy.rb) | Makes HTTP fun again |
102-
| [RestClient](https://github.com/rest-client/rest-client) | [rest_client_proxy.rb](ruby/rest_client_proxy.rb) | Simple REST client |
103-
| [Typhoeus](https://typhoeus.github.io/) | [typhoeus_proxy.rb](ruby/typhoeus_proxy.rb) | Fast HTTP client (libcurl wrapper) |
104-
| [HTTP.rb](https://github.com/httprb/http) | [http_rb_proxy.rb](ruby/http_rb_proxy.rb) | Simple Ruby DSL for HTTP |
105-
| [Excon](https://github.com/excon/excon) | [excon_proxy.rb](ruby/excon_proxy.rb) | Fast, simple HTTP(S) client |
106-
| [HTTPClient](https://github.com/nahi/httpclient) | [httpclient_proxy.rb](ruby/httpclient_proxy.rb) | LWP-like HTTP client |
107-
| [Mechanize](https://github.com/sparklemotion/mechanize) | [mechanize_proxy.rb](ruby/mechanize_proxy.rb) | Web automation library |
108-
109-
> **Note:** See [ruby-proxy-headers](https://github.com/proxymeshai/ruby-proxy-headers) for extensions that add custom proxy header support.
156+
| [Net::HTTP](https://docs.ruby-lang.org/en/master/Net/HTTP.html) (stdlib) | [net-http-proxy.rb](ruby/net-http-proxy.rb) | Low-level HTTP with proxy (`Net::HTTP.new` + proxy host/port/user/pass) |
157+
| [Faraday](https://lostisland.github.io/faraday/) | [faraday-proxy.rb](ruby/faraday-proxy.rb) | Middleware-style client; `Faraday.new(proxy: url)` |
158+
| [HTTParty](https://github.com/jnunemaker/httparty) | [httparty-proxy.rb](ruby/httparty-proxy.rb) | Simple API; `http_proxyaddr` / `http_proxyport` / credentials |
159+
| [HTTP.rb](https://github.com/httprb/http) | [http-rb-proxy.rb](ruby/http-rb-proxy.rb) | Lightweight DSL; proxy via `HTTP.via(host, port, user, pass)` |
160+
| [RestClient](https://github.com/rest-client/rest-client) | [rest-client-proxy.rb](ruby/rest-client-proxy.rb) | Simple REST API; proxy via `RestClient.proxy = url` |
161+
| [Typhoeus](https://github.com/typhoeus/typhoeus) | [typhoeus-proxy.rb](ruby/typhoeus-proxy.rb) | libcurl via Ethon; `proxy:` URL on the request |
162+
| [Excon](https://github.com/excon/excon) | [excon-proxy.rb](ruby/excon-proxy.rb) | Fast client; `Excon.get(url, proxy: url)` |
163+
| [HTTPClient](https://github.com/nahi/httpclient) | [httpclient-proxy.rb](ruby/httpclient-proxy.rb) | LWP-like client; pass full proxy URL to `HTTPClient.new` |
164+
| [Mechanize](https://github.com/sparklemotion/mechanize) | [mechanize-proxy.rb](ruby/mechanize-proxy.rb) | Crawling / forms; `set_proxy(host, port, user, password)` |
165+
| [Nokogiri](https://nokogiri.org/) | [nokogiri-proxy.rb](ruby/nokogiri-proxy.rb) | Parse HTML after a proxied `Net::HTTP` fetch |
166+
167+
Libraries above are actively maintained on RubyGems (releases within the last year as of early 2026). Like most high-level Ruby HTTP clients, they do not expose custom headers on the HTTPS `CONNECT` tunnel to the proxy or proxy response headers; for ProxyMesh-style custom proxy headers, lower-level clients or a dedicated helper library may be required.
110168

111169
## PHP Proxy Examples
112170

@@ -143,14 +201,78 @@ php php/run_tests.php
143201

144202
> **Note:** See [php-proxy-headers](https://github.com/proxymeshai/php-proxy-headers) for extensions that add custom proxy header support.
145203
146-
## Documentation
204+
These examples use [Bundler](https://bundler.io/). Install Ruby development headers and libcurl first so native extensions can compile (Debian/Ubuntu: `ruby-dev` and `libcurl4-openssl-dev`; Fedora: `ruby-devel` and `libcurl-devel`).
147205

148-
For more information on using proxy headers with Python:
206+
```bash
207+
cd ruby
208+
bundle install
209+
```
210+
211+
**Running examples:**
212+
213+
```bash
214+
# Required: set your proxy URL
215+
export PROXY_URL='http://user:pass@proxy.example.com:8080'
216+
217+
# Optional: target URL (default: https://api.ipify.org?format=json)
218+
export TEST_URL='https://httpbin.org/ip'
219+
220+
# Optional: print one response header
221+
export RESPONSE_HEADER='X-ProxyMesh-IP'
222+
223+
# Single example (from ruby/)
224+
bundle exec ruby faraday-proxy.rb
225+
226+
# All examples as tests
227+
bundle exec ruby run_tests.rb
228+
229+
# Specific examples
230+
bundle exec ruby run_tests.rb faraday typhoeus
231+
```
232+
233+
**Examples:**
234+
235+
| Library | Example | Description |
236+
|---------|---------|-------------|
237+
| [Net::HTTP](https://docs.ruby-lang.org/en/master/Net/HTTP.html) (stdlib) | [net-http-proxy.rb](ruby/net-http-proxy.rb) | Low-level HTTP with proxy (`Net::HTTP.new` + proxy host/port/user/pass) |
238+
| [Faraday](https://lostisland.github.io/faraday/) | [faraday-proxy.rb](ruby/faraday-proxy.rb) | Middleware-style client; `Faraday.new(proxy: url)` |
239+
| [HTTParty](https://github.com/jnunemaker/httparty) | [httparty-proxy.rb](ruby/httparty-proxy.rb) | Simple API; `http_proxyaddr` / `http_proxyport` / credentials |
240+
| [HTTP.rb](https://github.com/httprb/http) | [http-rb-proxy.rb](ruby/http-rb-proxy.rb) | Lightweight DSL; proxy via `HTTP.via(host, port, user, pass)` |
241+
| [RestClient](https://github.com/rest-client/rest-client) | [rest-client-proxy.rb](ruby/rest-client-proxy.rb) | Simple REST API; proxy via `RestClient.proxy = url` |
242+
| [Typhoeus](https://github.com/typhoeus/typhoeus) | [typhoeus-proxy.rb](ruby/typhoeus-proxy.rb) | libcurl via Ethon; `proxy:` URL on the request |
243+
| [Excon](https://github.com/excon/excon) | [excon-proxy.rb](ruby/excon-proxy.rb) | Fast client; `Excon.get(url, proxy: url)` |
244+
| [HTTPClient](https://github.com/nahi/httpclient) | [httpclient-proxy.rb](ruby/httpclient-proxy.rb) | LWP-like client; pass full proxy URL to `HTTPClient.new` |
245+
| [Mechanize](https://github.com/sparklemotion/mechanize) | [mechanize-proxy.rb](ruby/mechanize-proxy.rb) | Crawling / forms; `set_proxy(host, port, user, password)` |
246+
| [Nokogiri](https://nokogiri.org/) | [nokogiri-proxy.rb](ruby/nokogiri-proxy.rb) | Parse HTML after a proxied `Net::HTTP` fetch |
247+
248+
Libraries above are actively maintained on RubyGems (releases within the last year as of early 2026). Like most high-level Ruby HTTP clients, they do not expose custom headers on the HTTPS `CONNECT` tunnel to the proxy or proxy response headers; for ProxyMesh-style custom proxy headers, lower-level clients or a dedicated helper library may be required.
249+
250+
## Related Documentation
251+
252+
More examples and language-specific proxy-header tooling:
253+
254+
### Python
149255

150256
* [python-proxy-headers on PyPI](https://pypi.org/project/python-proxy-headers/)
151257
* [python-proxy-headers Documentation](https://python-proxy-headers.readthedocs.io/)
152-
* [GitHub Repository](https://github.com/proxymesh/python-proxy-headers)
258+
* [python-proxy-headers GitHub](https://github.com/proxymesh/python-proxy-headers)
259+
260+
### JavaScript / Node.js
261+
262+
* [javascript-proxy-headers GitHub](https://github.com/proxymesh/javascript-proxy-headers)
263+
* [javascript-proxy-headers on npm](https://www.npmjs.com/package/javascript-proxy-headers)
264+
* [javascript-proxy-headers on JSR](https://jsr.io/@proxymesh/javascript-proxy-headers)
265+
266+
### Ruby
267+
268+
* Ruby examples in this repository: [ruby/](ruby/)
153269

154270
## Contributing
155271

156-
If you have example code for another language, please share it with a Pull Request.
272+
Contributions are welcome for all supported languages in this repository (Python, JavaScript, Ruby, and PHP), as well as new language examples.
273+
274+
When opening a Pull Request:
275+
276+
* Follow the existing file naming and environment variable patterns (`PROXY_URL`, `TEST_URL`, and optional response/proxy header variables).
277+
* Include runnable examples and update the language section in this README.
278+
* Add or update the language test runner (`run_tests`) where applicable.

javascript/axios-proxy.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Axios with proxy example.
4+
*
5+
* Configuration via environment variables:
6+
* PROXY_URL - Proxy URL (required), e.g., http://user:pass@proxy:8080
7+
* TEST_URL - URL to request (default: https://api.ipify.org?format=json)
8+
*
9+
* Note: Axios does not support sending custom headers to the proxy during
10+
* HTTPS CONNECT tunneling, nor does it expose proxy response headers.
11+
* See: https://github.com/axios/axios/issues/3459
12+
*/
13+
import axios from 'axios';
14+
import { HttpsProxyAgent } from 'https-proxy-agent';
15+
16+
const proxyUrl = process.env.PROXY_URL || process.env.HTTPS_PROXY;
17+
if (!proxyUrl) {
18+
console.error('Error: Set PROXY_URL environment variable');
19+
process.exit(1);
20+
}
21+
22+
const testUrl = process.env.TEST_URL || 'https://api.ipify.org?format=json';
23+
24+
const agent = new HttpsProxyAgent(proxyUrl);
25+
26+
try {
27+
const response = await axios.get(testUrl, {
28+
httpsAgent: agent,
29+
httpAgent: agent,
30+
});
31+
32+
console.log(`Status: ${response.status}`);
33+
console.log(`Body: ${JSON.stringify(response.data)}`);
34+
} catch (error) {
35+
console.error(`Error: ${error.message}`);
36+
process.exit(1);
37+
}

javascript/cheerio-proxy.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Cheerio with node-fetch and proxy example.
4+
*
5+
* Configuration via environment variables:
6+
* PROXY_URL - Proxy URL (required), e.g., http://user:pass@proxy:8080
7+
* TEST_URL - URL to request (default: https://example.com)
8+
*
9+
* Cheerio is an HTML parser; this example shows how to combine it
10+
* with node-fetch for web scraping through a proxy.
11+
*
12+
* Note: The underlying HTTP client (node-fetch) does not support
13+
* custom proxy headers during HTTPS CONNECT.
14+
*/
15+
import * as cheerio from 'cheerio';
16+
import fetch from 'node-fetch';
17+
import { HttpsProxyAgent } from 'https-proxy-agent';
18+
19+
const proxyUrl = process.env.PROXY_URL || process.env.HTTPS_PROXY;
20+
if (!proxyUrl) {
21+
console.error('Error: Set PROXY_URL environment variable');
22+
process.exit(1);
23+
}
24+
25+
const testUrl = process.env.TEST_URL || 'https://api.ipify.org?format=json';
26+
27+
const agent = new HttpsProxyAgent(proxyUrl);
28+
29+
try {
30+
const response = await fetch(testUrl, { agent });
31+
const html = await response.text();
32+
33+
const $ = cheerio.load(html);
34+
const title = $('title').text();
35+
36+
console.log(`Status: ${response.status}`);
37+
console.log(`Title: ${title}`);
38+
console.log(`Body: ${html}`);
39+
} catch (error) {
40+
console.error(`Error: ${error.message}`);
41+
process.exit(1);
42+
}

javascript/got-proxy.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Got with proxy example.
4+
*
5+
* Configuration via environment variables:
6+
* PROXY_URL - Proxy URL (required), e.g., http://user:pass@proxy:8080
7+
* TEST_URL - URL to request (default: https://api.ipify.org?format=json)
8+
*
9+
* Note: Got does not support sending custom headers to the proxy during
10+
* HTTPS CONNECT tunneling, nor does it expose proxy response headers.
11+
* Got uses tunnel-agent under the hood for HTTPS proxying.
12+
*/
13+
import got from 'got';
14+
import { HttpsProxyAgent } from 'https-proxy-agent';
15+
16+
const proxyUrl = process.env.PROXY_URL || process.env.HTTPS_PROXY;
17+
if (!proxyUrl) {
18+
console.error('Error: Set PROXY_URL environment variable');
19+
process.exit(1);
20+
}
21+
22+
const testUrl = process.env.TEST_URL || 'https://api.ipify.org?format=json';
23+
24+
const agent = new HttpsProxyAgent(proxyUrl);
25+
26+
try {
27+
const response = await got(testUrl, {
28+
agent: {
29+
https: agent,
30+
},
31+
});
32+
33+
console.log(`Status: ${response.statusCode}`);
34+
console.log(`Body: ${response.body}`);
35+
} catch (error) {
36+
console.error(`Error: ${error.message}`);
37+
process.exit(1);
38+
}

0 commit comments

Comments
 (0)