Python httpx 隧道代理:异步 HTTP 四种 IP 控制场景

httpx 实现四种代理场景,重点展示 httpx.Proxy(headers=...) 在 CONNECT 阶段注入 Proxy-Tunnel 头支持 HTTPS。

亿牛云技术团队2026年5月17日2 分钟阅读

httpx 的优势

httpx 是 Python 生态中现代 HTTP 客户端,原生支持异步和 HTTP/2。在代理场景下,httpx 通过 httpx.Proxyheaders 参数,可以在 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.Proxyheaders 参数,在 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-HTTPShttpx.Proxy(headers=...)比 requests 简洁,无需自定义 Adapter

错误排查

# 先验证代理链路
curl -x http://$PROXY_USERNAME:$PROXY_PASSWORD@$PROXY_HOST:$PROXY_PORT https://httpbin.org/ip

遇到 407 请核对用户名密码,429 降低并发,504 重试。

需要企业代理方案?

我们可根据目标站点、并发规模与稳定性目标提供定制方案。