【问题标题】:What is the proper way to make downstream Https requests inside of Uvicorn/FastAPI?在 Uvicorn/FastAPI 内发出下游 Https 请求的正确方法是什么?
【发布时间】:2022-11-10 18:57:49
【问题描述】:

我有一个 API 端点(FastAPI / Uvicorn)。除此之外,它还向另一个 API 发出请求以获取信息。当我使用多个并发请求加载我的 API 时,我开始收到以下错误:

h11._util.LocalProtocolError: can't handle event type ConnectionClosed when role=SERVER and state=SEND_RESPONSE

在正常环境中,我会利用request.session,但我理解它不是完全线程安全的。

因此,在 FastAPI 等框架中使用请求的正确方法是什么,其中多个线程将同时使用 requests 库?

【问题讨论】:

    标签: python python-requests fastapi


    【解决方案1】:

    除了使用requests,您还可以使用httpx,它也提供async API(执行async 测试时的httpx is also suggested in FastAPI's documentation,以及最近的FastAPI/Starlettereplaced the HTTP client on TestClient from requests to httpx)。

    下面的示例基于httpx documentation 中给出的示例,演示了如何使用该库来发出异步 HTTP(s) 请求,然后将响应流式传输回客户端。 httpx.AsyncClient() 是您可以使用的,而不是 requests.Session(),这在向同一主机发出多个请求时很有用,因为底层 TCP 连接将被重用,而不是为每个请求重新创建一个,因此,在显着的性能提升。此外,它允许您在请求之间重用headers 和其他设置(例如proxiestimeout),以及持久化cookies。您生成一个 Client 并在每次需要时重复使用它。完成后,您可以使用await client.aclose()explicitly close the client(例如,您可以在shutdown event 处理程序中执行此操作)。示例和更多详细信息也可以在here 找到。

    from fastapi import FastAPI
    import httpx
    from starlette.background import BackgroundTask
    from fastapi.responses import StreamingResponse
    
    client = httpx.AsyncClient()
    app = FastAPI()
    
    @app.on_event('shutdown')
    async def shutdown_event():
        await client.aclose()
    
    @app.get('/')
    async def home():
        req = client.build_request('GET', 'https://www.example.com/')
        r = await client.send(req, stream=True)
        return StreamingResponse(r.aiter_text(), background=BackgroundTask(r.aclose))
    

    使用httpxasync API 意味着您必须使用async def 定义端点;否则,您将不得不使用standard synchronous API(对于defasync def,请参阅this answer),并如this github discussion 中所述:

    是的。 HTTPX旨在实现线程安全,是的,一个 跨所有线程的客户端实例在以下方面会做得更好 连接池,而不是使用每线程实例。

    您还可以使用Client 上的limits 关键字参数控制连接池大小(请参阅Pool limit configuration)。例如:

    limits = httpx.Limits(max_keepalive_connections=5, max_connections=10)
    client = httpx.Client(limits=limits)
    

    【讨论】:

    • 谢谢你的建议。我会马上试一试。如果它成功了,我会将此标记为答案。
    • 不,抱歉——这周真的很忙——仍在努力实施。
    猜你喜欢
    • 2022-01-23
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2014-09-23
    • 1970-01-01
    • 2022-08-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多