网络请求几乎是所有 Python 项目的基础动作之一,无论你是在写爬虫、脚本、自动化任务,还是 Web 服务,最终都要面对超时、失败、重试、连接复用和错误处理这些现实问题。
这一节我们会从最常见的 requests 讲起,再扩展到支持异步能力的 httpx,重点不只是会发请求,而是学会如何把请求写得更可靠、更适合进入项目。
从一次最简单的 HTTP 请求开始
最简单的请求当然不复杂:
import requests
response = requests.get("https://example.com")
print(response.text)但真实世界里的请求很快就会超出“拿到文本”这么简单。你通常还要关心:
- 状态码是不是成功;
- 会不会超时;
- 返回内容是不是期望格式;
- 失败时是否要重试;
- 这段逻辑要不要统一封装。
所以“会发请求”和“会写请求层”之间,其实隔着一整套稳定性设计。
requests:同步调用的主流选择
requests 之所以流行,很大程度上是因为它 API 友好、心智直接,非常适合同步脚本和普通阻塞式业务。
对于很多自动化脚本、后台任务或中小规模服务来说,只要不是高并发异步链路,requests 依然是很自然的选择。
不过它的优势也意味着边界很明确:它主要是同步模型。如果你的项目核心已经是异步链路,再硬塞 requests 进去,就会破坏整体调度方式。
httpx:兼顾同步与异步
httpx 的价值,在于它同时覆盖同步和异步使用场景,而且接口风格和 requests 有一定延续性。
这让它特别适合:
- 未来可能从同步过渡到异步的项目;
- 已经基于
asyncio或异步框架的服务; - 希望统一客户端抽象的团队。
所以 httpx 不只是“另一个请求库”,它更像是在现代 Python 工程里把请求能力和异步模型接得更顺的一种选择。
超时、重试与连接复用
真正可靠的请求层,至少要把这三件事想清楚。
第一是超时。没有超时的请求,本质上就是把系统命运交给对方服务。只要对方卡住,你这边就可能一直挂起。
第二是重试。重试不是越多越好,而是要区分哪些错误是短暂性波动,哪些错误重试也没有意义。
第三是连接复用。如果每次请求都重新建连接,性能和资源消耗都会比较差。会话级客户端或连接池机制能显著改善这件事。
这说明请求稳定性从来不是一个 get() 调用能解决的,而是围绕超时、失败策略和资源复用形成的一整套边界设计。
如何封装一个更可靠的请求层?
很多项目初期会直接在业务里到处写请求代码,但一旦接口变多、鉴权变复杂、日志和异常处理需要统一,散落调用就会变得很难维护。
更稳妥的做法通常是封装一层请求客户端,统一处理:
- 基础地址;
- 认证头;
- 超时设置;
- 状态码检查;
- 错误转换;
- 必要的日志。
这样业务层面对的就不再是一个裸 HTTP 库,而是一个更贴近项目语义的调用接口。
请求失败后应该如何处理?
请求失败不应该只有一个“抛异常然后算了”的粗糙策略。
你至少要区分:
- 网络层失败;
- 对方返回非 2xx 状态;
- 返回数据格式不合法;
- 业务语义错误。
不同失败类型,对应的处理方式往往不同。有的适合重试,有的适合直接上抛,有的要包装成统一业务异常,有的则要给上层更友好的错误说明。
所以请求层设计成熟与否,很多时候看的是它如何面对失败,而不是如何面对成功。
总结与预告
这一节我们把“会发请求”和“会写可靠请求”区分开了。请求层真正重要的从来不是调用某个 API,而是超时、重试、错误处理和封装边界这些决定稳定性的细节。
接下来我们会把前面的语言与工程能力带进 FastAPI,开始正式进入 Python Web 后端的框架实践阶段。