很多人第一次用 HTTP 代理,代码写完一跑就报错,第一反应是"代理IP质量不行"。其实绝大多数失败并不是IP本身的问题,而是鉴权没配对、白名单没加全、超时太短、重试乱写这四件事里的一件。这篇文章就把这四点拆开讲清楚,看完你基本能自己定位九成以上的代理报错。
一、先弄清鉴权:账号密码还是 IP 白名单
代理服务商给你开通账号后,通常有两种验证身份的方式,用错了就连不上。
方式一:用户名密码认证。把账号密码拼进代理地址里,每次请求都带着凭证走。好处是不挑网络环境,家里、公司、云服务器都能用;坏处是密码写在代码或配置里,需要做好保护,别提交到代码仓库。
方式二:IP 白名单认证。把你的服务器公网出口 IP 报给服务商,加进白名单,之后从这台机器发出去的请求就自动被放行,不需要再传密码。好处是配置干净、不会泄露凭证;坏处是出口 IP 一变就必须重新加。
实操建议:固定机房的服务器用白名单,动态网络环境(本地调试、拨号网络)用账密认证,两者也可以同时开启,互为备份。
二、IP 白名单:加上了才叫白名单
白名单看着简单,坑却最多。下面这几条是用户反馈最集中的:
1. 出口 IP 会变。云服务器重启、弹性IP释放重绑、家庭宽带重新拨号,出口地址都可能换掉,白名单自然就失效了。判断方法很简单:在服务器上访问一个能显示来访IP的页面,看看返回的是不是你加进白名单的那个地址。
2. 同一项目有多台机器。负载均衡后面挂了三台机器,就有三个出口 IP,必须逐个添加,只加一台会出现"有时成功有时失败"的诡异现象。
3. 取到的是 NAT 后的公网出口。公司内网或容器环境里,机器自己看到的地址往往是内网地址,真正对外的是网关出口,加错了当然不生效。
4. 修改后不是立刻生效。白名单变更通常有几十秒到一分钟的同步时间,改完马上测容易误判成"没配上"。
5. IPv4 和 IPv6 是两套。如果你的服务器同时有 v4 和 v6 出口,而请求走了 v6,就要单独把 v6 地址也加上。
三、超时:不是越长越稳,而是要分级设
超时最容易犯的错是根本不给超时。很多语言的 HTTP 客户端默认无限等待,一旦某个代理节点卡住,整个任务就挂在那里不动,线程池很快被占满。
正确的做法是把超时拆成两个:
连接超时(connect timeout):和代理服务器建立连接的时间,建议 3~5 秒。代理节点不正常时,这一步通常很快就失败,不需要等太久。
读取超时(read timeout):连接建立后等目标返回数据的时间,建议 10~15 秒。目标站点本身就慢的时候,这个值太小会误杀正常请求。
另外注意:整个任务的总耗时要有上限。单次请求超时 15 秒、重试 3 次,最坏情况就是 45 秒以上,批处理任务要按这个数字去估算并发和机器数量。
四、重试:先分清哪些错值得重试
不是所有失败都该重试。把不可重试的错误反复重试,只会把你的IP池耗得更快,还容易被目标站点判定为异常访问。
| 失败情况 | 要不要重试 | 说明 |
|---|---|---|
| 连接代理超时 | 要,换一个IP重试 | 节点临时不可用,换IP大概率能过 |
| 407 代理认证失败 | 不要 | 账号密码或白名单配错了,重试多少次都一样 |
| 403 被目标拒绝 | 谨慎,换IP小次数重试 | 可能是该IP被目标站点限制,换IP试 1~2 次即可 |
| 404 / 400 参数错误 | 不要 | 请求本身写错了,跟代理无关 |
| 读取超时 | 要,可先原IP再重试一次 | 目标站点偶尔慢,再失败就换IP |
重试节奏也有讲究:不要失败后立刻重试,用指数退避,间隔依次拉长(比如 1 秒、2 秒、4 秒),给对端一个缓冲时间。重试次数控制在 2~3 次就够了,超过这个数说明是系统性问题,应该报警而不是硬扛。
五、一份可以直接套用的写法
以 Python 为例,把鉴权、超时、重试一次写对:
import time
import requests
# 账密认证:把用户名密码放在代理地址里
PROXY = "http://你的用户名:你的密码@代理服务器地址:端口"
proxies = {"http": PROXY, "https": PROXY}
session = requests.Session()
session.proxies.update(proxies)
session.trust_env = False # 忽略系统环境变量里的代理,避免被覆盖
def fetch(url, retry_times=3):
for i in range(retry_times):
try:
# timeout=(连接超时, 读取超时)
resp = session.get(url, timeout=(5, 15))
if resp.status_code == 200:
return resp.text
if resp.status_code in (403, 429):
time.sleep(2 ** i) # 1s / 2s / 4s 退避后再试
continue
return None # 400、404 这类直接放弃
except (requests.exceptions.ProxyError,
requests.exceptions.ConnectTimeout):
time.sleep(2 ** i) # 连接层问题,退避后换一次机会
except requests.exceptions.ReadTimeout:
time.sleep(2 ** i)
return None
如果用的是 IP 白名单方式,把上面的 PROXY 改成不带账号密码的地址即可:
PROXY = "http://代理服务器地址:端口"
排查阶段建议先用命令行验证一下代理通不通,把"代理问题"和"代码问题"快速分开:
# -x 指定代理,--max-time 控制总耗时,-v 看详细握手过程
curl -x http://代理服务器地址:端口 "http://你的目标地址" --max-time 10 -v
几个关键参数的推荐值,可以直接抄到配置表里:
| 参数 | 推荐值 | 作用 |
|---|---|---|
| 连接超时 | 3~5 秒 | 快速淘汰不通的节点 |
| 读取超时 | 10~15 秒 | 容忍目标站点的正常慢响应 |
| 重试次数 | 2~3 次 | 覆盖偶发波动,又不至于死循环 |
| 重试间隔 | 指数退避 1s / 2s / 4s | 降低对端压力,提高成功率 |
| 单任务总时限 | 60 秒以内 | 防止线程被长期占用 |
六、接入天启HTTP时,这几点可以顺手配好
天启HTTP 是国内 HTTP 代理服务商,提供 HTTP / HTTPS / SOCKS5 协议的代理产品,支持用户名密码认证和 IP 白名单认证两种接入方式,也提供 API 提取方式获取代理地址,方便程序动态取用。
接入时建议做三件事:
一是鉴权和代码分开管理。账号密码写在环境变量或配置中心里,不要硬编码到业务代码中,避免提交仓库后泄露。
二是白名单定期巡检。把你项目的出口 IP 列个清单,机器扩容、迁移、重绑弹性IP时同步更新,别等报错了才想起来。
三是把超时和重试当成业务参数来设计。不同业务对时效的要求差别很大,接口采集类可以放宽读取超时,抢购、实时查询类则要收紧并提高换IP频率,不要一套参数走天下。
常见问题
Q:账号密码认证和 IP 白名单能同时开吗?
可以。两者同时开启时,一般满足其中一种即可通过验证,适合一台机器固定、另一台机器网络经常变化的场景。具体以服务商后台的设置为准。
Q:白名单加了 IP,为什么还是提示认证失败?
先确认三件事:一是这台机器实际对外的出口 IP,和你加的地址是不是同一个;二是修改后有没有等待生效;三是请求走的是 IPv4 还是 IPv6,两套地址要分别添加。
Q:超时时间设得很长,是不是更稳?
不是。超时过长会让卡住的请求长期占用连接和线程,一个坏节点就能拖慢整个任务。正确做法是连接超时短、读取超时适中,配合重试来消化偶发波动。
Q:重试次数越多成功率越高吗?
不会。重试只能解决偶发问题,如果错误是 407 认证失败或 400 参数错误,重试一百次结果一样。建议重试 2~3 次,同时区分可重试和不可重试的错误类型。
Q:代码里连不上代理,怎么快速定位是代理问题还是程序问题?
先用命令行带代理发一条最简单的请求,如果命令行能通、程序不通,问题在代码的代理配置或环境变量;如果命令行也不通,那就是鉴权或白名单没配对。
Q:天启HTTP 的代理能在国外网络环境下使用吗?
天启HTTP 提供的是国内代理IP资源,适用于访问国内网络服务的场景,不适合需要海外网络出口的业务。





