Python httpx Tunnel Proxy: Four IP Control Scenarios with Async HTTP
httpx implements four proxy scenarios. httpx.Proxy(headers=...) injects Proxy-Tunnel at the CONNECT stage for HTTPS targets.
16Yun Engineering TeamMay 17, 20261 min read
Why httpx
httpx is a modern async-capable HTTP client for Python. Its key advantage over requests in proxy scenarios: httpx.Proxy(headers=...) injects custom headers at the CONNECT stage natively — no custom Adapter needed.
Setup
export PROXY_HOST=t.16yun.cn
export PROXY_PORT=31111
export PROXY_USERNAME=your-username
export PROXY_PASSWORD=your-password
export PROXY_TUNNEL=httpx-demo-12345
Verify Proxy
curl -x http://$PROXY_USERNAME:$PROXY_PASSWORD@$PROXY_HOST:$PROXY_PORT https://httpbin.org/ip
Scenario A: Force New Connection
Create a new httpx.Client per request, disable connection pooling.
import os, httpx
host, port = os.getenv("PROXY_HOST","t.16yun.cn"), os.getenv("PROXY_PORT","31111")
user, pwd = os.getenv("PROXY_USERNAME","user"), os.getenv("PROXY_PASSWORD","password")
proxy_url = f"http://{user}:{pwd}@{host}:{port}"
for i in range(1, 4):
with httpx.Client(proxy=proxy_url, timeout=15.0,
limits=httpx.Limits(max_connections=1, max_keepalive_connections=0)) as client:
resp = client.get("https://httpbin.org/ip",
headers={"Connection":"close","Proxy-Connection":"close"})
print(f"Request {i}: {resp.json()['origin']}")
Scenario B: Keep-Alive Same IP
Reuse one httpx.Client with connection pooling enabled.
with httpx.Client(proxy=proxy_url, timeout=15.0,
limits=httpx.Limits(max_connections=5, max_keepalive_connections=5)) as client:
for i in range(1, 4):
resp = client.get("https://httpbin.org/ip",
headers={"Connection":"keep-alive","Proxy-Connection":"keep-alive"})
print(f"Request {i}: {resp.json()['origin']}")
Scenario C-HTTP: Proxy-Tunnel for HTTP
tunnel = os.getenv("PROXY_TUNNEL", "httpx-demo")
with httpx.Client(proxy=proxy_url, timeout=15.0) as client:
for i in range(1, 4):
resp = client.get("http://httpbin.org/ip",
headers={"Proxy-Tunnel":tunnel, "Connection":"keep-alive"})
print(f"Request {i}: {resp.json()['origin']}")
Scenario C-HTTPS: Proxy-Tunnel for HTTPS
This is where httpx shines. Use httpx.Proxy(headers=...) to inject Proxy-Tunnel at the CONNECT stage.
import httpx
tunnel = os.getenv("PROXY_TUNNEL", "httpx-demo")
proxy_url = f"http://{user}:{pwd}@{host}:{port}"
proxy = httpx.Proxy(url=proxy_url, headers={"Proxy-Tunnel": tunnel})
with httpx.Client(proxy=proxy, timeout=15.0) as client:
for i in range(1, 4):
resp = client.get("https://httpbin.org/ip",
headers={"Connection":"keep-alive"})
print(f"Request {i}: {resp.json()['origin']} (HTTPS Proxy-Tunnel)")
The headers in httpx.Proxy are sent during the HTTPS CONNECT handshake — no custom adapter required.
Scenario Comparison
| Scenario | httpx Approach | Compared to requests |
|---|---|---|
| A | New Client per request, no pool | Similar |
| B | Reuse Client with pool | Similar |
| C-HTTP | Proxy-Tunnel header on request | Same |
| C-HTTPS | httpx.Proxy(headers=...) | Simpler, no custom adapter |
Troubleshooting
| Status | Cause | Fix |
|---|---|---|
| 407 | Proxy auth failed | Verify credentials |
| 429 | Rate limit | Reduce concurrency |
| 504 | Target timeout | Retry 2-3 times |
Need an enterprise proxy plan?
We can tailor architecture to your target domains, concurrency, and reliability goals.