Python 的下一代 HTTP 客户端 HTTPX 特性详解

HTTPX是Python 的下一代 HTTP 客户端。(官网自称)

HTTPX 是一个功能全面的 Python 3 HTTP 客户端,提供同步和异步 API,并支持 HTTP/1.1 和 HTTP/2。

我们就将官网的特性逐一进行讲解。

1. 广泛兼容的 requests API

解释:

HTTPX 的设计目标之一是让熟悉 requests 库的用户几乎无需学习成本就能上手。它的核心 API(如 httpx.get(), httpx.post(), response.text, response.json() 等)与 requests 几乎一致。

代码
python 复制代码
# requests 风格
import httpx

resp = httpx.get("https://httpbin.org/get")
print(resp.status_code)
print(resp.json())

这段代码和用 requests 写法几乎一样,说明兼容性很好。

2. 标准同步接口,但也支持异步操作(如有需要)

解释:

HTTPX 同时提供了 同步客户端(httpx.Client) 和 异步客户端(httpx.AsyncClient)。

  • 同步:适合脚本、简单爬虫、非高并发场景。
  • 异步:适合高并发 I/O 密集型任务(如同时请求多个 API),需配合 async/await 使用。
同步示例:
python 复制代码
import httpx

with httpx.Client() as client:
    r = client.get("https://httpbin.org/delay/1")
    print(r.status_code)
异步示例(需在 async 环境中运行,如 Jupyter 或 asyncio.run):
python 复制代码
import asyncio
import httpx

async def main():
    async with httpx.AsyncClient() as client:
        r = await client.get("https://httpbin.org/delay/1")
        print(r.status_code)

asyncio.run(main())

3. 支持 HTTP/1.1 和 HTTP/2

解释:

HTTPX 默认使用 HTTP/1.1,但如果目标服务器支持 HTTP/2 且你安装了 httpx[http2](即 pip install httpx[http2]),它会自动协商使用 HTTP/2。HTTP/2 支持多路复用、头部压缩等,性能更好。

验证是否启用 HTTP/2:
python 复制代码
import httpx

# 需先安装: pip install httpx[http2]
with httpx.Client(http2=True) as client:
    r = client.get("https://http2.pro/")
    print("Using HTTP/2:", r.http_version == "HTTP/2")

4. 能够直接向 WSGI 应用 或 ASGI 应用 发起请求

解释:

通常我们通过网络(如 http://localhost:8000)测试 Web 应用。但 HTTPX 可以绕过网络层,直接调用 Python 的 WSGI(如 Flask/Django)或 ASGI(如 FastAPI/Starlette)应用对象,用于单元测试或集成测试,速度更快、更可靠。

  • WSGI(Web Server Gateway Interface)

    (1)诞生时间:2003 年(Python 社区标准,PEP 3333)

    (2)作用:定义了一个标准接口,让 Python Web 框架(如 Flask、Django)和 Web 服务器(如 Gunicorn、uWSGI)能够互相通信。

    (3)特点:

    同步:每个请求必须等前一个处理完才能开始。

    不支持 WebSocket、长连接、HTTP/2。

    只处理 HTTP。

    (4)典型框架:Flask、Django(默认模式)、Bottle。

  • ASGI(Asynchronous Server Gateway Interface)

    (1)诞生时间:2017 年左右(为支持现代 Web 需求而生)

    (2)作用:WSGI 的异步超集,同样是一个标准接口,但支持异步 I/O 和多种协议。

    (3)特点:

    异步:一个请求等待数据库时,可以去处理另一个请求。

    支持 WebSocket、HTTP/2、SSE(服务器推送)等。

    向后兼容 WSGI(可通过适配器运行 WSGI 应用)。

    (4)典型框架:FastAPI、Starlette、Quart(异步版 Flask)、Django 3.0+(部分支持)。

WSGI 示例(Flask):
python 复制代码
from flask import Flask
import httpx
from werkzeug.test import Client as WSGIClient
from httpx._transports.wsgi import WSGITransport

app = Flask(__name__)

@app.route("/hello")
def hello():
    return {"msg": "hi"}

# 使用 HTTPX 直接调用 WSGI app
transport = WSGITransport(app=app)
with httpx.Client(transport=transport, base_url="http://testserver") as client:
    r = client.get("/hello")
    print(r.json())  # {'msg': 'hi'}
ASGI 示例(FastAPI):
python 复制代码
from fastapi import FastAPI
import httpx
from httpx._transports.asgi import ASGITransport

app = FastAPI()

@app.get("/hello")
def hello():
    return {"msg": "hi"}

transport = ASGITransport(app=app)
with httpx.Client(transport=transport, base_url="http://testserver") as client:
    r = client.get("/hello")
    print(r.json())

这对测试非常有用,无需启动真实服务器。

5. 严格的全局超时控制

解释:

HTTPX 允许你设置连接超时(connect)、读取超时(read)、写入超时(write) 和连接池超时(pool)。默认超时是 5 秒,可通过 timeout 参数精细控制。

  • 连接超时(connect)指定等待与目标主机建立套接字连接的最长时间。如果 HTTPX 在此时间内无法建立连接,将引发 ConnectTimeout 异常。
  • 读取超时(read)指定等待接收数据块(例如响应体的一部分)的最长持续时间。如果 HTTPX 在此时间内无法接收数据,将引发 ReadTimeout 异常。
  • 写入超时(write)指定等待发送数据块(例如请求体的一部分)的最长持续时间。如果 HTTPX 在此时间内无法发送数据,将引发 WriteTimeout 异常。
  • 连接池超时(pool)指定从连接池获取连接的最长等待时间。如果 HTTPX 在此时间内无法获取连接,将引发 PoolTimeout 异常。与此相关的配置项是连接池允许的最大连接数,可通过 limits 参数进行配置。
示例:
python 复制代码
import httpx

# 设置所有阶段超时为 3 秒
try:
    r = httpx.get("https://httpbin.org/delay/5", timeout=3.0)
except httpx.TimeoutException:
    print("请求超时!")

也可以分别设置:

python 复制代码
timeout = httpx.Timeout(connect=1.0, read=2.0, write=1.0, pool=5.0)
r = httpx.get("https://example.com", timeout=timeout)

比 requests 的超时控制更细粒度(requests 只有 connect + read)。

python 复制代码
# 连接超时+读超时
response = requests.get(url, timeout=5)
# 分别设置连接超时和读超时。第一个数字是连接超时时间(Connect Timeout),第二个数字是读取超时时间(Read Timeout)
response = requests.get(url, timeout=(3, 5))

6. 完整的类型注解

解释:

HTTPX 所有函数、类、方法都带有 PEP 484 类型提示(Type Hints),配合 mypy 或 IDE(如 PyCharm、VSCode)可实现静态类型检查,减少 bug。

例如:
python 复制代码
def fetch(url: str) -> httpx.Response:
    return httpx.get(url)

resp: httpx.Response = fetch("https://example.com")

IDE 能自动提示 resp.status_code 是 int,resp.text 是 str 等。

7. 100% 测试覆盖率

解释:

这是指 HTTPX 的源代码每一行都被单元测试覆盖到(通过工具如 pytest-cov 验证)。这不保证没有 bug,但说明开发者非常重视质量,变更不易引入回归问题。

📌 这属于项目质量指标,对用户透明,但让你用得更放心。

8. 以及 requests 的所有标准功能...

接下来这些其实是 requests 的经典功能,HTTPX 也都支持:

国际化域名和 URL(IDN)
解释:

支持包含非 ASCII 字符的域名,如 https://例子.测试,HTTPX 会自动将其转换为 Punycode(如 例.测试)。

  • Punycode背景

互联网早期,域名只允许使用 ASCII 字符(a-z, 0-9, -)。

但中文、阿拉伯文、俄文等用户也希望用自己的语言注册域名,比如:

复制代码
https://例子.测试

但 DNS 系统(域名解析底层)不认非 ASCII 字符!

于是,人们发明了 Punycode ------ 一种编码规则,把 Unicode 域名转换成纯 ASCII 字符串。

  • Punycode是什么
    定义:一种将 Unicode 字符串(如中文、emoji)编码为 ASCII 字符串的算法。
    格式:以 xn-- 开头,后面是编码后的字母数字组合。
    目的:让国际化域名(IDN, Internationalized Domain Names)能在现有 DNS 系统中工作。
示例:
python 复制代码
import httpx

# 注意:这个域名可能不存在,仅演示编码
url = "https://例子.测试"
print(httpx.URL(url))  # 自动转为 punycode 形式

✅ 实际请求时,DNS 解析会处理转换。

保持连接和连接池
解释:

HTTPX 会复用 TCP 连接(HTTP Keep-Alive),避免每次请求都新建连接。Client 对象内部维护连接池,提升性能。

示例:
python 复制代码
import httpx

with httpx.Client() as client:
    for _ in range(3):
        r = client.get("https://httpbin.org/get")
        print(r.status_code)
# 三次请求复用同一个连接(如果服务器支持)
解释:

Client 会自动保存服务器返回的 Cookie,并在后续请求中自动携带。

示例:
python 复制代码
import httpx

with httpx.Client() as client:
    # 第一次请求设置 cookie
    client.get("https://httpbin.org/cookies/set?name=value")
    # 第二次请求自动带 cookie
    r = client.get("https://httpbin.org/cookies")
    print(r.json())  # {'cookies': {'name': 'value'}}
浏览器式 SSL 验证
解释:

默认启用 SSL 证书验证(使用系统 CA 证书),防止中间人攻击。和浏览器一样严格。

示例(正常情况):
python 复制代码
r = httpx.get("https://github.com")  # 验证通过
禁用验证(不推荐):
python 复制代码
r = httpx.get("https://self-signed.badssl.com", verify=False)

✅ 安全默认开启。

基本/摘要认证
解释:

支持 HTTP Basic Auth 和 Digest Auth。

Basic Auth 示例:
python 复制代码
r = httpx.get("https://httpbin.org/basic-auth/user/pass", auth=("user", "pass"))
print(r.status_code)  # 200 if ok
Digest Auth 需要 httpx.DigestAuth(注意:requests 有,HTTPX 从 v0.23+ 开始支持):
python 复制代码
# 需要服务器支持 digest auth
auth = httpx.DigestAuth("user", "pass")
r = httpx.get("https://httpbin.org/digest-auth/auth/user/pass", auth=auth)
解释:

可手动设置 Cookie,像字典一样操作。

示例:
python 复制代码
cookies = {"session_id": "abc123"}
r = httpx.get("https://httpbin.org/cookies", cookies=cookies)
print(r.json())
自动解压缩
解释:

如果服务器返回 gzip、deflate 等压缩内容,HTTPX 会自动解压,你拿到的是原始内容。

示例:
python 复制代码
r = httpx.get("https://httpbin.org/gzip")
print(r.json()["gzipped"])  # True,但你无需手动解压
自动内容解码
解释:

根据响应头的 Content-Type(如 charset=utf-8),自动将 bytes 解码为 str(通过 .text 属性)。

示例:
python 复制代码
r = httpx.get("https://httpbin.org/encoding/utf8")
print(type(r.text))  # <class 'str'>
Unicode 响应体
解释:

支持任意 Unicode 字符,不会乱码(前提是服务器正确声明编码)。

多部分文件上传
解释:

支持 multipart/form-data 上传文件,类似 HTML 表单。

示例:
python 复制代码
files = {"file": ("test.txt", b"Hello World")}
r = httpx.post("https://httpbin.org/post", files=files)
print(r.json()["files"])

也可上传真实文件:

python 复制代码
with open("test.txt", "rb") as f:
    files = {"file": f}
    r = httpx.post("https://httpbin.org/post", files=files)
HTTP(S) 代理支持
解释:

可通过 proxies 参数设置 HTTP/HTTPS/SOCKS 代理。

示例:
python 复制代码
proxies = {"http://": "http://10.10.1.10:3128", "https://": "http://10.10.1.10:3128"}
r = httpx.get("https://example.com", proxies=proxies)
连接超时

已在上面第 5 条"严格的全局超时控制"中涵盖。只是比requests更加细致。

流式下载
解释:

对于大文件,可逐块(chunk)读取,避免一次性加载到内存。

示例:
python 复制代码
with httpx.stream("GET", "https://httpbin.org/stream-bytes/1024") as r:
    for chunk in r.iter_bytes(chunk_size=128):
        print(len(chunk))  # 每次 128 字节
.netrc 支持
解释:

如果存在 ~/.netrc 文件,HTTPX 会自动读取其中的认证信息(用户名/密码)用于对应域名。

.netrc文件

.netrc 是一个"自动填账号密码"的小本本,放在你电脑的家目录里,专门给命令行工具(比如 curl、httpx、ftp)用,避免每次都要手动输用户名和密码。

  1. 文件位置
  • Linux / macOS:~/.netrc(即 /home/你的用户名/.netrc 或 /Users/你的用户名/.netrc)
  • Windows:通常不支持,或需通过环境变量指定(HTTPX 在 Windows 上对 .netrc 支持有限)

⚠️ 注意:这个文件必须权限设为 600(仅自己可读写),否则很多工具会拒绝使用(安全考虑):

复制代码
chmod 600 ~/.netrc
  1. 文件格式(非常简单)
    .netrc 是纯文本文件,内容长这样:

    machine httpbin.org
    login alice
    password secret123

    machine api.example.com
    login bob
    password mypass456

每一组由三行组成:

  • machine 域名:指定这个账号密码用于哪个网站(只写域名,不要带 http://)
  • login 用户名
  • password 密码

你可以为多个网站分别配置。

  1. 它解决了什么问题?
    假设你有一个 API 接口需要 Basic Auth 认证:
python 复制代码
# 没有 .netrc 时,你必须在代码里写死账号密码(不安全!)
r = httpx.get("https://httpbin.org/basic-auth/alice/secret123", auth=("alice", "secret123"))

但如果你把账号密码写在代码里:

  • 容易被提交到 Git(泄露!)
  • 换密码要改代码
  • 多人协作麻烦
    ✅ 有了 .netrc,你的代码可以完全不出现密码:
python 复制代码
# 代码干净又安全!
r = httpx.get("https://httpbin.org/basic-auth/alice/secret123")

只要 .netrc 里配了 machine httpbin.org 的账号密码,HTTPX 会自动读取并加上 Basic Auth 头!

  1. 那如果代码里同时写了 auth 和 .netrc,以代码里的 auth 为准,.netrc 被忽略。
示例(需先创建 ~/.netrc):
python 复制代码
machine httpbin.org
login user
password pass

然后

python 复制代码
r = httpx.get("https://httpbin.org/basic-auth/user/pass")  # 自动带 auth
分块请求(Chunked Transfer Encoding)
解释:

当你发送的数据长度未知时,可使用分块传输(无需提前知道 Content-Length)。

示例:
python 复制代码
def data_generator():
    yield b"part1"
    yield b"part2"

r = httpx.post("https://httpbin.org/post", content=data_generator())

总结

HTTPX = requests 的易用性 + 异步 + HTTP/2 + 类型安全 + 现代架构。

无论是写脚本、做测试、还是构建高性能服务,它都是目前 Python 最先进的 HTTP 客户端之一。

参考文献

HTTPX官网
HTTPX中文官网

相关推荐
hcnaisd22 小时前
机器学习模型部署:将模型转化为Web API
jvm·数据库·python
果粒蹬i2 小时前
Python + AI:打造你的智能害虫识别助手
开发语言·人工智能·python
阿钱真强道2 小时前
09 jetlinks-mqtt-属性主动上报-windows-python-实现
开发语言·windows·python·网络协议
Blossom.1182 小时前
从单点工具到智能流水线:企业级多智能体AI开发工作流架构实战
人工智能·笔记·python·深度学习·神经网络·架构·whisper
亚林瓜子2 小时前
pyspark添加一列时间戳数据并改名
python·spark
2401_841495642 小时前
【机器学习】标准化流模型(NF)
人工智能·python·机器学习·标准化流模型·概率生成模型·可逆变换·概率密度变换
Blossom.1182 小时前
从“金鱼记忆“到“超级大脑“:2025年AI智能体记忆机制与MoE架构的融合革命
人工智能·python·算法·架构·自动化·whisper·哈希算法
CresCent_Charles2 小时前
(源代码)CloudComPy+open3d实现点云配准项目(手动选点配准+ICP点云配准+误差显示)
python·点云·配准·点云配准
写代码的【黑咖啡】2 小时前
Python 中的 Gensim 库详解
开发语言·python