You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Uvicorn/FastAPI中发起下游HTTP请求的正确方式是什么?

FastAPI并发场景下正确使用requests库的方案

错误原因解析

你遇到的h11._util.LocalProtocolError: can't handle event type ConnectionClosed when role=SERVER and state=SEND_RESPONSE错误,本质是requests.Session的线程不安全特性导致的。Session的连接复用机制在多线程共享实例时,会出现连接状态混乱——比如一个线程正在发送响应,另一个线程却关闭了共享连接,触发协议状态冲突。

三种正确使用方式

1. 单请求独立创建实例(最简单)

如果对性能要求不高,直接在接口里每次调用requests.get/post,每个请求用独立的连接,完全规避线程安全问题。
示例代码:

from fastapi import FastAPI
import requests

app = FastAPI()

@app.get("/fetch-external-data")
def fetch_data():
    # 每次请求都新建请求实例
    response = requests.get("https://目标外部API地址")
    response.raise_for_status()
    return response.json()

缺点:没有连接复用,高并发下会频繁建立/销毁TCP连接,性能略差。

2. 线程局部存储隔离Session(兼顾复用与安全)

利用threading.local为每个线程分配独立的Session实例,既保留连接复用的性能优势,又避免线程间的状态干扰。
示例代码:

from fastapi import FastAPI
import requests
import threading

app = FastAPI()
# 线程局部存储,每个线程拥有专属Session
thread_local = threading.local()

def get_thread_session():
    if not hasattr(thread_local, "session"):
        thread_local.session = requests.Session()
    return thread_local.session

@app.get("/fetch-external-data")
def fetch_data():
    session = get_thread_session()
    response = session.get("https://目标外部API地址")
    response.raise_for_status()
    return response.json()

优点:平衡了连接复用和线程安全,适合需要复用连接的高并发场景。

3. 切换异步HTTP客户端(最优解)

FastAPI本身支持异步,改用httpx.AsyncClient这类异步客户端,完全契合框架的异步模型,天然支持高并发,不存在线程安全问题,性能也更优。
示例代码(单次请求创建客户端):

from fastapi import FastAPI
import httpx

app = FastAPI()

@app.get("/fetch-external-data")
async def fetch_data():
    async with httpx.AsyncClient() as client:
        response = await client.get("https://目标外部API地址")
        response.raise_for_status()
        return response.json()

如果要复用连接池,可全局管理客户端实例:

from fastapi import FastAPI
import httpx

app = FastAPI()
async_client = None

@app.on_event("startup")
async def init_client():
    global async_client
    async_client = httpx.AsyncClient()

@app.on_event("shutdown")
async def close_client():
    await async_client.aclose()

@app.get("/fetch-external-data")
async def fetch_data():
    response = await async_client.get("https://目标外部API地址")
    response.raise_for_status()
    return response.json()

这是FastAPI并发场景下最推荐的方案,异步架构+连接池复用能最大化性能。

总结

  • 低并发场景:直接用requests单请求实例,简单省心。
  • 需要连接复用的高并发场景:用线程局部存储隔离Session。
  • 追求最优性能:切换到httpx异步客户端,适配FastAPI异步模型。

内容的提问来源于stack exchange,提问作者SteveJ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 06:25:22