【问题标题】:Using FastAPI in a sync way, how can I get the raw body of a POST request?以同步方式使用 FastAPI,如何获取 POST 请求的原始正文
【发布时间】:2022-08-08 02:15:13
【问题描述】:

使用 FastAPI同步,而不是异步模式,我希望能够接收原始的、未更改的发布请求正文。

我能找到的所有示例都显示异步代码,当我以正常同步方式尝试时,request.body() 将 uo 显示为协程对象。

当我通过向该端点发布一些 XML 来测试它时,我得到一个 500 \"Internal Server Error\"

from fastapi import FastAPI, Response, Request, Body

app = FastAPI()


@app.get(\"/\")
def read_root():
    return {\"Hello\": \"World\"}

@app.post(\"/input\")
def input_request(request: Request):

    # how can I access the RAW request body here?  
    body = request.body()

    # do stuff with the body here  

    return Response(content=body, media_type=\"application/xml\")

这对 FastAPI 来说是不可能的吗?

注意:简化的输入请求看起来像

POST http://127.0.0.1:1083/input
Content-Type: application/xml

<XML>
    <BODY>TEST</BODY>
</XML>

而且我无法控制输入请求的发送方式,因为我需要替换现有的 SOAP API

    标签: python fastapi


    【解决方案1】:

    如果对象是协程,则需要等待。 FastAPI 基于 Starlette。用于返回请求正文的Starlette methodsasync 方法;因此,需要await 他们。

    更新 1

    或者,如果您确信传入的数据是有效的JSON,则可以使用Body 字段,如下所示:

    @app.post("/input")
    def input_request(payload: dict = Body(...)):
        return payload
    

    但是,如果传入的数据是 XML 格式,就像您提供的示例一样,最好通过 files 传递它们,如下所示 - 只要您可以控制客户端数据的格式发送。

    @app.post("/input") 
    def input_request(file: bytes = File(...)): 
        return file
    

    更新 2

    this post 中所述,您可以使用async dependency 函数从请求中提取body。您也可以在 non-async 端点上使用 async 依赖项。因此,如果此端点中有某种阻塞代码阻止您使用async/await——我猜这可能是你的情况的原因——这就是要走的路。

    注意:我还应该提到this answer——它解释了defasync def路由之间的区别(你可能知道)——也提供了当你需要使用async def时的解决方案(你可能需要await 用于路由内的协程),但也有一些同步可能阻塞服务器的昂贵的 CPU 密集型操作。请看一看。

    可以在下面找到前面描述的方法的示例。您可以取消注释time.sleep() 行,如果您想确认一个请求不会阻止其他请求通过,因为该路由已使用def 定义(不管async def 依赖函数) .

    from fastapi import FastAPI, Depends, Request
    import time
    
    app = FastAPI()
    
    async def get_body(request: Request):
        return await request.body()
    
    @app.post("/input")
    def input_request(body = Depends(get_body)):
        print("New request arrived.")
        #time.sleep(5)
        return body
    

    【讨论】:

    • 同步没有等待,这就是我问的原因。 FastAPI毕竟支持同步请求......
    • 只要由他们的 API 声明,就可以read the body of the request。但是,使用前面提到的方法获取请求的原始正文需要等待,如FastAPI is actually Starlette underneath。另外,请看讨论here
    • 我会检查并回到这个
    • “文件”方法返回“HTTP/1.1 422 无法处理的实体”。我在原始问题中添加了一个示例请求。注意:我无法控制客户端请求的外观,因为我正在重新创建旧 SOAP API,以便能够将请求从旧系统重新路由到将替换旧服务的 Python 服务。
    • 我已经用可能适合您的解决方案进一步更新了答案。请看一看。希望能帮助到你。
    猜你喜欢
    • 2018-06-24
    • 2022-06-17
    • 2021-10-01
    • 1970-01-01
    • 2019-01-07
    • 2013-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多