# Python HTTPX 代理接入示例

使用 HTTPX Client、账密环境变量和分层超时完成同步代理请求。

HTTPX 适合同步服务和需要连接池的 Python 项目。HTTPS 目标仍通过 HTTP 代理 URL 建立 CONNECT 隧道，代理地址格式为 `http://<gateway-host>:<gateway-port>`。

## 前置条件

- 调用方项目自行安装并锁定 `httpx`。
- 从控制台取得当前有效的网关、端口、代理用户名和密码。
- 通过受控环境注入 `PROXY_HOST`、`PROXY_PORT`、`PROXY_USERNAME` 和 `PROXY_PASSWORD`。

## 完整示例

```python
import os
from urllib.parse import quote

import httpx

proxy_username = quote(os.environ["PROXY_USERNAME"], safe="")
proxy_password = quote(os.environ["PROXY_PASSWORD"], safe="")
proxy_host = os.environ["PROXY_HOST"]
proxy_port = os.environ["PROXY_PORT"]
proxy_url = (
    f"http://{proxy_username}:{proxy_password}"
    f"@{proxy_host}:{proxy_port}"
)
timeout = httpx.Timeout(30.0, connect=10.0)

with httpx.Client(proxy=proxy_url, timeout=timeout) as client:
    response = client.get("https://<public-test-host>/ip")
    response.raise_for_status()
    print(response.json())
```

## 预期结果

- 请求返回成功状态并显示代理出口 IP。
- 返回地区应与代理用户名中的地区参数一致；随机区域以本次实际出口为准。
- 同一个 `Client` 可以复用连接，不要为每个请求重复创建客户端。

## 错误处理

- 收到 407 时先检查完整用户名、密码和当前套餐权益。
- `ConnectTimeout` 表示代理连接阶段超时，`ReadTimeout` 表示等待目标响应超时。
- 只对可安全重放的请求做有限退避重试。

## 安全提示

不要记录 `proxy_url`、请求头或异常对象中的完整代理信息。日志只保留任务标识、目标主机、错误类型和脱敏后的 requestId。

html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}
