Python httpx:高效能的次世代同步與非同步 HTTP 用戶端
在 Python 的世界裡,requests 長期以來都是處理 HTTP 請求的首選。然而,隨著 AsyncIO 非同步程式設計的普及,requests 因為不支援非同步操作,在處理高併發任務時顯得有些力不從心。
HTTPX 是一個完全相容於 requests API 介面,且原生支援 非同步 (Async) 與 HTTP/2 的次世代 HTTP 用戶端函式庫。
為什麼選擇 HTTPX?
- 高度相容:它的 API 幾乎與
requests一模一樣,轉換成本極低。 - 原生非同步:提供了
AsyncClient,能完美整合到 FastAPI 或其他非同步框架中。 - HTTP/2 支援:支援現代化的協定,能提升連線效率。
- 強型別支援:更符合現代化的開發習慣。
安裝 HTTPX
pip install httpx
如果你需要 HTTP/2 支援,則安裝:
pip install httpx[http2]
基礎語法:同步請求 (與 requests 幾乎相同)
如果你習慣 requests,你可以直接上手 httpx:
import httpx
# 同步 GET 請求
response = httpx.get("https://httpbin.org/get", params={"key": "value"})
print(f"狀態碼: {response.status_code}")
print(f"回應內容: {response.json()}")
# 同步 POST 請求
payload = {"name": "httpx"}
response = httpx.post("https://httpbin.org/post", json=payload)
核心亮點:非同步請求 (AsyncClient)
這是 httpx 最強大的地方。在非同步環境(如 FastAPI)中,你必須使用 AsyncClient。
import httpx
import asyncio
async def fetch_data():
# 使用 AsyncClient 作為上下文管理器
async with httpx.AsyncClient() as client:
response = await client.get("https://httpbin.org/get")
print(f"Async Response: {response.status_code}")
async def main():
# 同時發送多個請求
tasks = [fetch_data() for _ in range(5)]
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
使用 Client 提升效能 (Connection Pooling)
無論是同步還是非同步,如果你需要對同一個伺服器發送多次請求,建議使用 Client 物件。這會啟用 連線池 (Connection Pooling),重複使用傳輸層連線,大幅提升效能。
同步版本
with httpx.Client() as client:
for i in range(10):
r = client.get(f"https://example.com/api/{i}")
非同步版本
async with httpx.AsyncClient() as client:
# 這裡的連線會被重用
r = await client.get("https://example.com")
HTTPX vs Requests 比較表
| 特性 | Requests | HTTPX |
|---|---|---|
| API 設計 | 非常人性化 | 延續 Requests 風格 (高度相似) |
| 非同步支援 | ❌ 需搭配 grequests 等套件 | ✅ 原生支援 AsyncClient |
| HTTP/2 支援 | ❌ 不支援 | ✅ 支援 |
| 強型別 / Type Hints | 基礎 | ✅ 完整支援 |
| 預設超時 | ❌ 預設不超時 (容易卡死) | ✅ 預設 5 秒超時 (更安全) |
超時與錯誤處理
httpx 非常重視安全性,預設情況下所有請求都有 5 秒的超時限制(requests 預設是無限期等待)。
import httpx
try:
# 自訂超時
response = httpx.get("https://example.com", timeout=10.0)
# 檢查狀態碼,若非 2xx 則拋出異常
response.raise_for_status()
except httpx.TimeoutException:
print("請求超時了!")
except httpx.HTTPStatusError as exc:
print(f"HTTP 錯誤回傳: {exc.response.status_code}")
總結
- 如果你的專案是純同步的,
requests依然很好用。 - 如果你正在開發 FastAPI 或任何非同步應用,HTTPX 是你的唯一首選。
- 它不僅提供了與
requests一樣好用的介面,還帶來了 HTTP/2 與更安全的預設超時設定。