大家好,我是木木。
今天给大家分享一个稳健的 Python 库,httpx。
httpx
如果你熟悉 requests,但项目里又开始出现异步调用、连接池复用、严格超时、HTTP/2 或者“直接打进 ASGI 应用测试”的需求,httpx 会是一个很自然的升级选择。它保留了很顺手的请求体验,又把同步、异步和传输层扩展都收进同一套模型里。
项目地址:https://github.com/encode/httpx
官方文档:https://www.python-httpx.org/
三大特点
接口熟悉
整体用法接近 requests,普通 GET、POST、JSON、headers 和 cookies 都能很快上手。
同步异步统一
Client 和 AsyncClient 的心智模型一致,项目从同步脚本走到异步服务时迁移成本更低。
传输层灵活
WSGI、ASGI、MockTransport、HTTP/2 和代理路由都能接进去,测试和集成会更好写。
最佳实践
安装方式:python -m pip install httpx
这篇我不依赖外部接口,全部用本地服务或内存 transport 来演示。重点看三件事:如何用 Client 管好会话状态,如何用 AsyncClient 直接测 ASGI 应用,以及如何用 MockTransport 把外部服务替换成可控结果。
功能一:用 Client 统一管理 base_url、headers、cookies 和 timeout
这段代码解决什么问题:真实项目里,你通常不会每次都裸调 httpx.get(),而是会固定一个服务地址、统一请求头、带着 cookie 或 token 连续访问。Client 可以把这些共同配置收在一起,也能复用连接池。
importjsonimportthreadingimporttimefromhttp.serverimportBaseHTTPRequestHandler,ThreadingHTTPServerimporthttpxPORT=18941classHandler(BaseHTTPRequestHandler):defdo_POST(self):ifself.path=="/login":size=int(self.headers.get("Content-Length","0"))payload=json.loads(self.rfile.read(size)orb"{}")body=json.dumps({"user":payload.get("name"),"client":self.headers.get("X-Client")}).encode()self.send_response(200)self.send_header("Content-Type","application/json")self.send_header("Set-Cookie","session=demo-token; Path=/")self.send_header("Content-Length",str(len(body)))self.end_headers()self.wfile.write(body)else:self.send_response(404)self.end_headers()defdo_GET(self):ifself.path.startswith("/profile"):body=json.dumps({"path":self.path,"cookie":self.headers.get("Cookie")}).encode()self.send_response(200)self.send_header("Content-Type","application/json")self.send_header("Content-Length",str(len(body)))self.end_headers()self.wfile.write(body)else:self.send_response(404)self.end_headers()deflog_message(self,fmt,*args):passserver=ThreadingHTTPServer(("127.0.0.1",PORT),Handler)thread=threading.Thread(target=server.serve_forever,daemon=True)thread.start()time.sleep(0.1)try:withhttpx.Client(base_url=f"http://127.0.0.1:{PORT}",headers={"X-Client":"httpx-demo"},timeout=2.0)asclient:login=client.post("/login",json={"name":"wood"})profile=client.get("/profile",params={"tab":"overview"})print("login :",login.status_code,login.json())print("cookie:",client.cookies.get("session"))print("profile:",profile.status_code,profile.json())finally:server.shutdown()server.server_close()

这个模式适合内部 API SDK、后台任务和各种脚本客户端。你可以把共同配置收进一个 Client,业务代码里只关心“访问哪个资源”和“传什么参数”。
功能二:用 AsyncClient 直接调用 ASGI 应用
这段代码解决什么问题:异步 Web 项目里,经常要在测试里直接请求应用本身,而不是先真的起一个端口。ASGITransport 可以让 AsyncClient 直接打进 ASGI app,速度快,也更容易写成稳定测试。
importasyncioimportjsonimporthttpxasyncdefapp(scope,receive,send):assertscope["type"]=="http"payload={"path":scope["path"],"query":scope["query_string"].decode(),"client":scope.get("client"),}body=json.dumps(payload).encode()awaitsend({"type":"http.response.start","status":200,"headers":[(b"content-type",b"application/json")]})awaitsend({"type":"http.response.body","body":body})asyncdefmain():transport=httpx.ASGITransport(app=app,client=("10.0.0.8",4210))asyncwithhttpx.AsyncClient(transport=transport,base_url="http://asgi.local")asclient:response=awaitclient.get("/health",params={"probe":"ready"})print("status:",response.status_code)print("url :",response.url)print("json :",response.json())asyncio.run(main())
这对 FastAPI、Starlette 这类 ASGI 项目很有用。你可以不用真实网络端口,也能验证路由、查询参数、请求来源和响应结构。
环境与版本信息
- Demo 环境:Windows 11,Python 3.11
- 关键依赖:
httpcore、anyio、certifi、idna - 仓库
pyproject.toml 当前要求 Python >=3.9 - GitHub 最近一次推送时间:
2026-03-29T00:19:16Z
高级功能
这段代码解决什么问题:调用第三方接口时,测试最怕结果不可控。MockTransport 可以把外部服务换成本地 handler,再配合 response hook 记录链路,适合单元测试、离线开发和回归脚本。
importhttpxtrace=[]defhandler(request):trace.append(f"send {request.method}{request.url.path}")ifrequest.url.path=="/orders/42":returnhttpx.Response(200,json={"id":42,"state":"paid"},headers={"X-Upstream":"mock"})returnhttpx.Response(404,json={"error":"missing"})defon_response(response):trace.append(f"recv {response.status_code}{response.headers.get('X-Upstream','-')}")transport=httpx.MockTransport(handler)withhttpx.Client(transport=transport,base_url="https://api.example.com",event_hooks={"response":[on_response]})asclient:response=client.get("/orders/42")print("status:",response.status_code)print("state :",response.json()["state"])print("trace :"," | ".join(trace))
这个能力很适合把“外部支付服务”“短信接口”“内部网关”先抽成可控响应。等测试通过后,再把 transport 换回真实 HTTPTransport,就能减少很多环境依赖。
适用场景
- 你需要一个比
requests 更适合现代项目的 HTTP 客户端,同时保留熟悉的 API 手感 - 你的项目同时有同步脚本和异步服务,希望请求层尽量统一
- 你要做 ASGI/WSGI 内测、Mock 外部接口、HTTP/2 或更细的 transport 配置
不适用场景
- 你只做极少量一次性同步请求,项目已经稳定依赖
requests,没有迁移收益 - 你要的是浏览器自动化、页面渲染或 WebSocket 客户端能力,HTTPX 的重点不在这些方向
- 你的团队还没有准备好管理异步生命周期,却想把所有请求都改成异步
上线检查
- 先统一
timeout 策略,不要让请求在异常网络下无限等待 - 长期运行的服务里尽量复用
Client 或 AsyncClient,不要在热路径里反复创建 - 对第三方接口先用
MockTransport 做回归样例,再用少量真实环境请求做集成验证
总结
如果你想把 Python 里的 HTTP 调用从“能用”推进到“同步异步统一、测试好写、边界更稳”,httpx 是非常值得放进工具箱的一类库。