Python HTTP请求底层包含DNS解析、TCP握手、TLS协商(HTTPS)、HTTP交互四环节;DNS解析影响超时,TCP复用连接池,TLS校验证书,HTTP处理头体边界,任一环故障都可能导致错误提示失真。

Python 中发起 HTTP 请求看似简单,但底层连接建立过程涉及 DNS 解析、TCP 握手、TLS 协商(HTTPS)、HTTP 协议交互等多个环节。理解这条链路,能帮你快速定位超时、连接拒绝、SSL 错误等常见问题。
DNS 解析:域名到 IP 的第一步
requests 或 urllib 发起请求时,若 URL 使用域名(如 https://api.github.com),Python 会调用系统 getaddrinfo() 获取 IP 地址。这步可能被缓存、被 hosts 文件覆盖,也可能因 DNS 服务器响应慢或失败而卡住。
- 可通过 socket.gethostbyname("example.com") 手动测试解析是否正常
- requests 支持传入 proxies 参数,但 DNS 解析默认仍走本地;如需强制走代理 DNS,需配合自定义 resolver(如 dnslib + requests.adapters.HTTPAdapter)
- 超时控制:requests 的 timeout=(connect, read) 中,connect 超时包含 DNS 解析时间
TCP 连接建立:三次握手与连接池复用
拿到 IP 后,Python 底层 socket 发起 TCP 连接。requests 默认使用 urllib3 的连接池(PoolManager),会复用已有空闲连接,避免重复握手开销。
- 首次请求耗时通常更高,后续同 host 请求可能直接复用连接(Connection: keep-alive)
- 可查看连接状态:response.raw._connection.pool.num_connections(需开启 debug 日志或 inspect urllib3.PoolManager)
- 连接被拒绝(ConnectionRefusedError)一般表示目标端口未监听,或防火墙拦截;连接超时(TimeoutError)更可能是网络不可达或中间设备丢包
TLS 握手(仅 HTTPS):证书验证与加密协商
HTTPS 请求在 TCP 建立后立即进入 TLS 握手阶段,包括协议版本协商、密钥交换、证书校验等。这是 SSL 错误(如 CERTIFICATE_VERIFY_FAILED、SSLError)的高发环节。
立即学习“Python免费学习笔记(深入)”;
- requests 默认启用证书验证,依赖 certifi 包内置的 CA 证书列表
- 内网服务用自签名证书时,可传入 verify=False(不推荐)或指定 verify="/path/to/cert.pem"
- TLS 版本限制:urllib3 1.26+ 默认禁用 TLS 1.0/1.1;如需兼容旧服务,可通过 PoolManager(ssl_version=ssl.PROTOCOL_TLSv1_2) 强制指定
HTTP 请求发送与响应接收:头与体的边界处理
TCP+TLS 就绪后,才真正发出 HTTP 请求行、头部和可选 body。服务端返回响应时,客户端需按 HTTP 协议解析状态行、headers 和 body 流。
- Content-Length 或 Transfer-Encoding: chunked 决定如何读取响应体;requests 自动处理,但流式响应(stream=True)需手动迭代 response.iter_content()
- 重定向由 requests 默认跟随(max_redirects=30),可通过 allow_redirects=False 观察原始 302 响应
- 若卡在“等待响应头”,可能是服务端未写入响应、长连接挂起,或代理(如 Nginx)配置了 proxy_buffering off 且后端响应异常
不复杂但容易忽略。链路中任一环出问题,都会表现为请求失败,而错误提示未必指向真实原因——比如 DNS 失败可能报 timeout,TLS 验证失败可能被包装成 ConnectionError。动手前先分段验证,比盲目调参数更有效。










