Python httpx 隧道代理:异步 HTTP 四种 IP 控制场景
httpx 实现四种代理场景,重点展示 httpx.Proxy(headers=...) 在 CONNECT 阶段注入 Proxy-Tunnel 头支持 HTTPS。
亿牛云技术团队2026年5月17日2 分钟阅读
httpx 的优势
httpx 是 Python 生态中现代 HTTP 客户端,原生支持异步和 HTTP/2。在代理场景下,httpx 通过 httpx.Proxy 的 headers 参数,可以在 HTTPS CONNECT 阶段直接添加自定义头——无需像 requests 那样自定义 Adapter。
环境准备
export PROXY_HOST=t.16yun.cn
export PROXY_PORT=31111
export PROXY_USERNAME=your-username
export PROXY_PASSWORD=your-password
export PROXY_TUNNEL=python-httpx-demo-12345
场景 A:强制切换 IP
每次请求创建新的 httpx.Client,禁用连接池,强制 IP 切换。
import os
import httpx
host = os.getenv("PROXY_HOST", "t.16yun.cn")
port = os.getenv("PROXY_PORT", "31111")
user = os.getenv("PROXY_USERNAME", "user")
pwd = 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"请求 {i}: {resp.json()['origin']}")
每次创建新 Client,max_keepalive_connections=0 禁用连接池,确保 TCP 不复用。
场景 B:Keep-Alive 保持相同 IP
复用同一个 httpx.Client,启用连接池,保持相同出口 IP。
import os
import httpx
proxy_url = f"http://{user}:{pwd}@{host}:{port}"
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"请求 {i}: {resp.json()['origin']}")
场景 C-HTTP:Proxy-Tunnel 固定 IP(HTTP 目标)
import os
import httpx
tunnel = os.getenv("PROXY_TUNNEL", "httpx-demo")
proxy_url = f"http://{user}:{pwd}@{host}:{port}"
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"请求 {i}: {resp.json()['origin']} (Proxy-Tunnel)")
场景 C-HTTPS:Proxy-Tunnel 固定 IP(HTTPS 目标)
这是 httpx 相比 requests 的核心优势:通过 httpx.Proxy 的 headers 参数,在 CONNECT 阶段直接注入 Proxy-Tunnel。
import os
import httpx
tunnel = os.getenv("PROXY_TUNNEL", "httpx-demo")
proxy_url = f"http://{user}:{pwd}@{host}:{port}"
# 关键:通过 httpx.Proxy 的 headers 参数在 CONNECT 阶段携带 Proxy-Tunnel
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"请求 {i}: {resp.json()['origin']} (HTTPS Proxy-Tunnel)")
httpx.Proxy(headers=...)中的头会在 HTTPS CONNECT 握手时发送给代理服务器,代理据此分配固定 IP。requests 需要自定义 HTTPAdapter 才能达到同样效果。
场景对比
| 场景 | httpx 实现要点 | 与 requests 的差异 |
|---|---|---|
| A | 每次新建 Client,禁连接池 | 类似 |
| B | 复用 Client,启连接池 | 类似 |
| C-HTTP | 请求头加 Proxy-Tunnel | 相同 |
| C-HTTPS | httpx.Proxy(headers=...) | 比 requests 简洁,无需自定义 Adapter |
错误排查
# 先验证代理链路
curl -x http://$PROXY_USERNAME:$PROXY_PASSWORD@$PROXY_HOST:$PROXY_PORT https://httpbin.org/ip
遇到 407 请核对用户名密码,429 降低并发,504 重试。
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。