我有以下 FastAPI 应用程序:
from pydantic import BaseModel as Schema
from fastapi import FastAPI
api = FastAPI()
class User(Schema):
firstname: str
lastname: str
age: int | None = None
@api.post('/user')
def user_selection(user: User):
return {'data': f'{user.firstname} {user.lastname} age: {user.age}'}
主文件名为
file.py
,所以我像这样运行uvicorn服务器:
uvicorn file:api --reload
通过另一个控制台,我发送此请求:
curl -X 'POST' -i 'http://127.0.0.1:8000/user' -d '{firstname":"mike", "lastname":"azer"}'
但是,我收到此错误:
HTTP/1.1 422 Unprocessable Entity
date: Sun, 05 Feb 2023 16:01:14 GMT
server: uvicorn
content-length: 88
content-type: application/json
{"detail":[{"loc":["body"],"msg":"value is not a valid dict","type":"type_error.dict"}]}
这是为什么?
但是,如果我在请求中将
Content-Type
标头设置为 application/json
:
curl -X 'POST' 'http://127.0.0.1:8000/user' -H 'Content-Type: application/json' -d '{
"firstname": "aaa",
"lastname": "zzz"
}'
它有效很好。
为什么需要标题?当我执行
GET
请求时,我不必添加标头并且它可以工作。与 POST
请求有何不同?
问:“为什么 JSON POST 请求中需要 Content-Type 标头?”
curl
的文档:
使用curl的
选项进行POST将使其包含默认标头 看起来像-d
。 这就是您的典型浏览器用于普通 POST 的方式。Content-Type: application/x-www-form-urlencoded
许多 POST 数据的接收者并不关心或检查 内容类型标头。
如果该标题对您来说不够好,您当然应该, 替换它并提供正确的一个。例如,如果您发布 JSON 到服务器并希望更准确地告诉服务器 内容是什么:
curl -d '{json}' -H 'Content-Type: application/json' https://example.com
因此,在发送包含 JSON 数据的
'Content-Type: application/json'
请求时需要 POST
标头的原因很简单,因为 curl
默认情况下使用 application/x-www-form-urlencoded
Content-Type 对构成请求正文的数据进行编码—这是浏览器在提交 HTML 时通常使用的方式 <form>
。
但是,如果
files
也包含在请求中,则 multipart/form-data
内容类型将由 curl
使用 自动— 这同样适用于使用 Python 请求,如 this 答案 所示(对于 HTML表单,您需要手动指定
enctype
,如此处所示)—根据curl
的文档:
发布二进制文件
从文件中读取要发布的数据时,
将删除回车符和换行符。如果您有以下情况,请使用-d
想要curl完全按照给定的方式读取和使用给定的二进制文件:--data-binary
curl --data-binary @filename http://example.com/
我还建议您查看相关答案here、here和here,以及使用/docs
处的
interactive Swagger UI autodocs来测试API,它也会自动生成用于测试 API 端点的
curl
命令。
问:“当我发出
GET
请求时,我不需要添加标头,它就可以工作。与POST
请求有什么区别?”
A:发出
GET
请求时,不包含请求体,因此不需要编码请求体内容,也不需要告诉服务器正在发送什么类型的数据。在 GET
请求中,所有参数必须出现在 URL(即查询字符串)或标头中。虽然 HTTP 标准没有定义 URL 或标头的长度限制,但通常存在长度限制,具体取决于服务器和客户端(通常在 2KB 到 8KB 之间)。然而,在 POST
请求中,限制要高得多,并且比客户端更依赖于服务器。