FastAPI - 如何在 HTTP 多部分请求中传递字典/JSON 数据?

问题描述 投票:0回答:1

我正在尝试提出一个

POST
请求:

import requests


files = {'template': open('template.xlsx', 'rb')}
payload = {
    'context': {
        'OUT': 'csv',
        'SHORT': 'short'
    },
    'filename': 'file.xlsx',
    'content_type': 'application/excel'
}

r = requests.post('http://localhost:8000/render', files=files, data=payload)

到 FastAPI 服务器:

from fastapi import FastAPI, UploadFile, Form
from pydantic import Json

app = FastAPI()


@app.post('/render')
def render(template: UploadFile, context: Json = Form(), filename: str = Form(...), content_type: str = Form(...)):
    # processing
    return "ok"

但是我得到这个错误(

422
状态代码):

{"detail":[{"loc":["body","context"],"msg":"Invalid JSON","type":"value_error.json"}]}

如您所见,我正在尝试同时通过

file
request body
。我想如果将
payload['context']
转换为 JSON 我可以解决这个问题。但我想在服务器端解决这个问题。

如何修复错误?也许在参数传递到视图之前转换一些或类似的东西?

python json python-requests fastapi multipartform-data
1个回答
0
投票

在发送请求之前,您需要使用

json.dumps()
在客户端序列化您的 JSON。此外,您实际上不需要发送元数据,例如
filename
content_type
作为 JSON 负载的一部分。您可以在
multipart-encoded file
中明确设置
filename
(您可以自定义)和content_type,稍后您可以使用
UploadFile
属性
在服务器端检索。此外,
content_type
(或
mime type
)文件的
.xlsx
不应该是
application/excel
,但是,如herehere所述,应该是
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
。最后,我还建议你看看这个答案,它解释了你不能同时拥有
form-data
/
files
JSON
的原因,并提供了允许一个人的解决方案提交两者,并验证 JSON 数据——在您的情况下,JSON 数据未针对 Pydantic 模型进行验证,这意味着客户端可以发送任何类型的数据或省略任何
required
属性。

app.py

from fastapi import FastAPI, UploadFile, Form, File
from pydantic import Json

app = FastAPI()

@app.post('/render')
def render(file: UploadFile = File(...), context: Json = Form()):
    print(context, context['OUT'], file.filename, file.content_type, sep="\n")
    return "ok"

test.py

import requests
import json

url = 'http://localhost:8000/render'
files = {'file': ('file.xlsx', open('template.xlsx', 'rb'), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')}
payload = {'context': json.dumps({'OUT': 'csv','SHORT': 'short'})}
r = requests.post(url, files=files, data=payload)
print(r.json())
© www.soinside.com 2019 - 2024. All rights reserved.