我正在尝试使用 FastAPI/Mangum 创建无服务器文件上传 API,但在尝试遵循文档中的示例时遇到了奇怪的 JSON 解码问题。
这是我的代码:
# main.py
import os
from typing import List
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse
from mangum import Mangum
app = FastAPI()
@app.get("/")
async def main():
content = """
<body>
<form action="/registration/create" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)
@app.post("/registration/create")
async def create_registration(files: List[UploadFile]):
return {"file_len": len(files)}
handler = Mangum(app)
# test_main.py
from urllib import response
from fastapi.testclient import TestClient
from main import app
client = TestClient(app)
def test_registration():
files = [('files', ('example.txt', open('example.txt', 'rb'), 'text/plain'))]
response = client.post("/registration/create", files=files)
assert response.status_code == 200
当我运行测试或尝试使用网页示例访问
POST
文件时,我收到 JSON 解码错误,并且请求失败并显示 422
状态代码错误:
{
"detail":
[{"loc":["body",0],
"msg":"Expecting value: line 1 column 1 (char 0)",
"type":"value_error.jsondecode",
"ctx": {
"msg": "Expecting value",
"doc": "\nContent-Disposition: form-data; name=\\"files\\"; filename=\\"example.txt\\"\\r\\nContent-Type: text/plain\\r\\n\\r\\nexample text in the file\n",
"pos":0,
"lineno":1,
"colno":1
}
}]
}
这是我引用的docs页面。
您收到的错误只是表明您的 FastAPI 端点按照定义的方式需要 JSON 数据,这是因为您没有指定
UploadFile
的类型,即使用 = File(...)
。因此,FastAPI 将 List[UploadFile]
解释为 JSON 主体。
您的端点应该如下所示:
from fastapi import File
@app.post("/registration/create")
async def create_registration(files: List[UploadFile] = File(...)):
return {"file_len": len(files)}
在最新版本的FastAPI中,您可以定义类型为
UploadFile
的文件参数,而无需在参数的默认值中使用= File()
或
= File(...)
。因此,以下内容也应该按预期工作:
@app.post("/registration/create")
async def create_registration(files: List[UploadFile]):
return {"file_len": len(files)}
工作示例多文件上传文档。
from fastapi import FastAPI, UploadFile
from fastapi.responses import HTMLResponse
from typing import List
app = FastAPI()
@app.post("/files/")
async def create_files(files: List[UploadFile]):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)