Smi*_*ith 15 python python-requests axios fastapi
我正在构建一个简单的 API 来测试数据库。当我使用 get request 时一切正常,但如果我更改为 post,我会收到“无法处理的实体”错误:
这是 FastAPI 代码:
from fastapi import FastAPI
app = FastAPI()
@app.post("/")
def main(user):
return user
Run Code Online (Sandbox Code Playgroud)
然后,我的请求使用 javascript
let axios = require('axios')
data = {
user: 'smith'
}
axios.post('http://localhost:8000', data)
.then(response => (console.log(response.url)))
Run Code Online (Sandbox Code Playgroud)
并使用 Python
import requests
url = 'http://127.0.0.1:8000'
data = {'user': 'Smith'}
response = requests.post(url, json=data)
print(response.text)
Run Code Online (Sandbox Code Playgroud)
我也尝试解析为 json,使用 utf-8 编码,并更改标题。没有什么对我有用。
Chr*_*ris 62
422具有( ) 状态代码的响应unprocessable entity将具有指定错误消息的响应正文,准确说明请求的哪一部分丢失或与\xe2\x80\x99 不匹配预期格式。您提供的代码片段显示您正在尝试将JSON数据发布到期望user作为query参数而不是JSON有效负载的端点。因此,出现422 unprocessable entity错误。下面给出了关于如何定义期望数据的端点的四种不同选项JSON。
根据文档,当您需要将JSON数据从客户端(比如说浏览器)发送到您的 API 时,您可以将其作为请求正文发送(通过POST请求)。要声明请求正文,您可以使用Pydantic模型。
from pydantic import BaseModel\n\nclass User(BaseModel):\n user: str\n\n@app.post(\'/\')\ndef main(user: User):\n return user\nRun Code Online (Sandbox Code Playgroud)\n如果不想使用 Pydantic 模型,也可以使用Body参数。如果使用单个 body 参数(如您的示例中所示),您可以使用特殊的Body参数embed。
\nfrom fastapi import Body\n\n@app.post(\'/\')\ndef main(user: str = Body(..., embed=True)):\n return {\'user\': user}\nRun Code Online (Sandbox Code Playgroud)\n另一种(不太推荐)方法是使用Dict类型(或简单地dict在 Python 3.9+ 中)来声明一个key:value对。但是,通过这种方式,您不能JSON像使用 Pydantic 模型或那样对您预期的各种属性使用自定义验证Body字段那样对您预期的各种属性使用自定义验证(例如,检查电子邮件地址是否有效,或者字符串是否遵循特定模式) 。
from typing import Dict, Any\n\n@app.post(\'/\')\ndef main(payload: Dict[Any, Any]): \n return payload\nRun Code Online (Sandbox Code Playgroud)\n在上面的示例中,payload也可以定义为payload: dict[Any, Any],或简单地定义为payload: dict。
如果您确信传入的数据是有效的JSON,则可以直接使用Starlette 的Request对象来将请求正文解析为JSON,使用await request.json()。但是,使用这种方法,您不仅不能对属性使用自定义验证,而且还需要使用 定义端点async def,因为request.json()是一种async方法,因此需要await它(看看这个答案有关defvs的更多详细信息async def)。
from fastapi import Request\n\n@app.post(\'/\')\nasync def main(request: Request): \n return await request.json()\nRun Code Online (Sandbox Code Playgroud)\n如果您愿意,您还可以Content-Type在尝试解析数据之前对请求标头值进行一些检查,类似于此答案。然而,仅仅因为请求application/json在Content-Type标头中说明,并不总是意味着这是真的,或者传入的数据是有效的JSON(即,可能缺少大括号,有一个没有值的键) , ETC)。因此,try-except当您尝试解析数据时,您可以使用块,让您处理任何数据JSONDecodeError,以防您的数据处理方式出现问题。JSON,以防数据格式化
from fastapi import Request, HTTPException\nfrom json import JSONDecodeError\n\n@app.post(\'/\')\nasync def main(request: Request):\n content_type = request.headers.get(\'Content-Type\')\n \n if content_type is None:\n raise HTTPException(status_code=400, detail=\'No Content-Type provided\')\n elif content_type == \'application/json\':\n try:\n return await request.json()\n except JSONDecodeError:\n raise HTTPException(status_code=400, detail=\'Invalid JSON data\')\n else:\n raise HTTPException(status_code=400, detail=\'Content-Type not supported\')\nRun Code Online (Sandbox Code Playgroud)\n如果您希望端点接受特定/预定义和任意 JSON 数据,请检查此答案。
\n相关答案可以在这里找到。
\nimport requests\n\nurl = \'http://127.0.0.1:8000/\'\npayload ={\'user\': \'foo\'}\nresp = requests.post(url=url, json=payload)\nprint(resp.json())\nRun Code Online (Sandbox Code Playgroud)\n相关答案也可以在这里和这里找到。有关使用的示例axios,请查看这个答案,以及这个答案和这个答案。
fetch(\'/\', {\n method: \'POST\',\n headers: {\n \'Content-Type\': \'application/json\'\n },\n body: JSON.stringify({\'user\': \'foo\'})\n })\n .then(resp => resp.json()) // or, resp.text(), etc\n .then(data => {\n console.log(data); // handle response data\n })\n .catch(error => {\n console.error(error);\n });\nRun Code Online (Sandbox Code Playgroud)\n
Sun*_*arg 49
就我而言,我从不同的 python 项目调用 python API,如下所示
queryResponse = requests.post(URL, data= query)
Run Code Online (Sandbox Code Playgroud)
我正在使用 data 属性,我将其更改为 json,然后它对我有用
queryResponse = requests.post(URL, json = query)
Run Code Online (Sandbox Code Playgroud)
Ala*_*lan 17
如果您正在使用fetchAPI 并且仍然收到422 Unprocessable Entity,请确保您已设置Content-Type标头:
fetch(someURL, {
method: "POST",
headers: {
"Content-type": "application/json"
},
body
}).then(...)
Run Code Online (Sandbox Code Playgroud)
这解决了我的案例中的问题。在服务器端,我使用 Pydantic 模型,所以如果您不使用这些模型,请参阅上面的答案。
小智 15
直接来自文档:
函数参数将被识别如下:
- 如果参数也在path 中声明,它将用作路径参数。
- 如果参数是单一类型(如 int、float、str、bool 等),它将被解释为查询参数。
- 如果参数被声明为Pydantic 模型的类型,它将被解释为请求正文。”
因此,要创建一个接收带有用户字段的正文的 POST 端点,您可以执行以下操作:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Data(BaseModel):
user: str
@app.post("/")
def main(data: Data):
return data
Run Code Online (Sandbox Code Playgroud)
FastAPI 基于Python 类型提示,因此当您传递查询参数时,它接受key : value对,您需要以某种方式声明它。
即使像这样的东西也会起作用
from typing import Dict, Any
...
@app.post("/")
def main(user: Dict[Any, Any] = None):
return user
Out: {"user":"Smith"}
Run Code Online (Sandbox Code Playgroud)
但使用Pydantic方式更有效
class User(BaseModel):
user: str
@app.post("/")
def main(user: User):
return user
Out: {"user":"Smith"}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
28947 次 |
| 最近记录: |