当 FastAPI 端点需要 Pydantic 模型并且通过字符串传递模型时,它会按预期工作,除非该字符串包含 unicode 字符。
首先,我使用示例模型为 FastAPI 创建一个示例应用程序。
serv.py
from pydantic import BaseModel
class exClass(BaseModel):
id: int = Field(example=1)
text: str = Field(example="Text example")
app = FastAPI(debug=True)
@app.post("/example")
async def receive_pyd(ex: exClass):
print(ex)
return True
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="127.0.0.1", port=8000)
显示相关错误的客户端
client.py
from pydantic import BaseModel, Field
import requests
class exClass(BaseModel):
id: int = Field(example=1)
text: str = Field(example="Text example")
ex1 = exClass(id=1, text="working example")
ex2 = exClass(id=2, text="this’ will fail")
ex3 = exClass(id=3, text="🤗 <- also non-working")
r = requests.post(f"http://127.0.0.1:8000/example", data=ex1.model_dump_json())
print(r.text)
r = requests.post(f"http://127.0.0.1:8000/example", data=ex2.model_dump_json())
print(r.text)
r = requests.post(f"http://127.0.0.1:8000/example", data=ex3.model_dump_json())
print(r.text)
输出:
true
Invalid HTTP request received.
Invalid HTTP request received.
当
text
包含 unicode 字符时,结果是 422 Unprocessable Entity。我尝试过 ex.dict()、model_dump(),并在请求调用中使用 json 而不是数据。在 FastAPI/starlette 中启用调试会冒出无效的 HTTP 请求是 JSON 解码错误。
这不是Pydantic和FastAPI的问题。您应该对请求数据进行编码,如下所示:
r = requests.post(
f"http://127.0.0.1:8000/example", data=ex1.model_dump_json().encode('utf-8')
)
print(r.text)
r = requests.post(
f"http://127.0.0.1:8000/example", data=ex2.model_dump_json().encode('utf-8')
)
print(r.text)
r = requests.post(
f"http://127.0.0.1:8000/example", data=ex3.model_dump_json().encode('utf-8')
)
print(r.text)
从 Python
requests
发送 JSON 数据时,应使用 json
参数来传递有效的字典。使用该参数会将请求的 Content-Type
标头设置为 application/json
。另一方面, data
参数在发送表单数据时使用,这些数据使用 application/x-www-form-urlencoded
(即 Content-Type
中的默认 requests
)或 multipart/form-data
(如果 files
)进行编码也包含在请求中)。
请查看这个答案和这个答案。您可能会发现这个答案,以及这个答案和这个答案也很有帮助。
除了将
Content-Type
标头设置为 application/json
之外,您还应该使用 Pydantic 的 model_dump()
方法(有关更多详细信息,请参阅 这个答案),而不是 model_dump_json()
,这会将模型转换为字典。
from pydantic import BaseModel, Field
import requests
class Example(BaseModel):
id: int = Field(example=1)
text: str = Field(example="test")
ex1 = Example(id=1, text="Working")
ex2 = Example(id=2, text="this’ will also work")
ex3 = Example(id=3, text="🤗 <- will also work")
url = 'http://127.0.0.1:8000/example'
r = requests.post(url, json=ex1.model_dump())
print(r.text)
r = requests.post(url, json=ex2.model_dump())
print(r.text)
r = requests.post(url, json=ex3.model_dump())
print(r.text)