likeadmin和fastapi的bug

以下内容写于2023年8月11日

bug 1

请求体 - 多个参数 - FastAPI (tiangolo.com)中“请求体中的单一值”处,选python3.6,接口示例代码是

from typing import Unionfrom fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotatedapp = FastAPI()class Item(BaseModel):name: strdescription: Union[str, None] = Noneprice: floattax: Union[float, None] = Noneclass User(BaseModel):username: strfull_name: Union[str, None] = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User, importance: Annotated[int, Body()]
):results = {"item_id": item_id, "item": item, "user": user, "importance": importance}return results

根据给的请求体的示例代码,我写的请求代码是

import requestsurl = 'http://127.0.0.1:8000/items/7'
form_data = {"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2},"user": {"username": "dave","full_name": "Dave Grohl"},"importance": 5
}
response = requests.put(url=url, json=form_data)
print(response.status_code)
print(response.text)

若新建一个python3.8的环境(装好是3.8.17,称为likeadmin环境),然后按照likeadmin的requirements.txt安装库,运行服务端接口代码,再运行请求代码,不能得到正确的结果,提示

{"detail":[{"loc":["query","importance"],"msg":"field required","type":"value_error.missing"}]}

若新建一个python3.8的环境(装好是3.8.17,称为纯fastapi环境),然后pip install fastapi[all],运行服务端接口代码,再运行请求代码,能得到正确的结果

{"item_id":7,"item":{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2},"user":{"username":"dave","full_name":"Dave Grohl"},"importance":5}

判断结果是否正确的依据是文档中的一句话“在这种情况下,FastAPI 将期望像这样的请求体”。

likeadmin的环境要想得到正确的结果,查看127.0.0.1:8000/docs得知应把importance用问号拼接在请求url中,因为自动生成的文档显示它是query即查询参数。

likeadmin的环境自动生成的文档
纯fastapi环境自动生成的文档

 总结一下就是likeadmin的环境运行fastapi的示例代码,无法得到fastapi文档中说的预期的结果;而新建一个相同python版本的虚拟环境,里面只pip install fastapi[all],可以得到fastapi文档中说的预期的结果。

截止到2023年8月11日,likeadmin的requirements.txt的内容是

aiofiles==22.1.0
aiomysql==0.1.1
alibabacloud_dysmsapi20170525==2.0.23
alibabacloud_tea_openapi
anyio==3.6.1
async-timeout==4.0.2
click==8.1.3
colorama==0.4.5
commonmark==0.9.1
cos-python-sdk-v5==1.9.22
databases==0.6.1
Deprecated==1.2.13
fastapi==0.85.0
fastapi-cache2==0.1.9
fastapi-pagination==0.10.0
greenlet==1.1.3.post0
h11==0.14.0
httptools==0.5.0
idna==3.4
Jinja2==3.1.2
MarkupSafe==2.1.1
optionaldict==0.1.2
oss2==2.16.0
pendulum==2.1.2
psutil==5.9.3
pydantic==1.10.2
Pygments==2.13.0
PyMySQL==1.0.2
python-dateutil==2.8.2
python-dotenv==0.21.0
python-multipart==0.0.5
pytz==2022.5
pytzdata==2020.1
PyYAML==6.0
qiniu==7.9.0
redis==4.4.0rc2
rich==12.6.0
shellingham==1.5.0
six==1.16.0
sniffio==1.3.0
SQLAlchemy==1.4.41
starlette==0.20.4
tencentcloud-sdk-python==3.0.841
typer==0.6.1
typing-extensions==4.4.0
ua-parser==0.16.1
user-agents==2.2.0
# uvloop==0.17.0
uvicorn==0.18.3
watchfiles==0.17.0
websockets==10.3
wrapt==1.14.1
wechatpy==1.8.18

bug 2

与bug1类似,也是likeadmin的环境运行fastapi的示例代码,无法得到fastapi文档中说的预期的结果;而新建一个相同python版本的虚拟环境,里面只pip install fastapi[all],可以得到fastapi文档中说的预期的结果。

请求体 - 多个参数 - FastAPI (tiangolo.com)中“嵌入单个请求体参数”处,选python3.6,接口示例代码是

from typing import Unionfrom fastapi import Body, FastAPI
from pydantic import BaseModel
from typing_extensions import Annotatedapp = FastAPI()class Item(BaseModel):name: strdescription: Union[str, None] = Noneprice: floattax: Union[float, None] = None@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Annotated[Item, Body(embed=True)]):results = {"item_id": item_id, "item": item}return results

文档中说“在这种情况下,FastAPI 将期望像这样的请求体:”

{"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2}
}

而不是:

{"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2
}

根据给的请求体的示例代码,我写的请求代码是

import requestsurl = 'http://127.0.0.1:8000/items/7'
form_data_1 = {"item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2}
}
form_data_2 = {# "item": {"name": "Foo","description": "The pretender","price": 42.0,"tax": 3.2# }
}
response_1 = requests.put(url=url, json=form_data_1)
response_2 = requests.put(url=url, json=form_data_2)
print(response_1.status_code)
print(response_1.text)
print(response_2.status_code)
print(response_2.text)
# 上面的打印结果:
# fastapi环境
# 200
# {"item_id":7,"item":{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2}}
# 422
# {"detail":[{"type":"missing","loc":["body","item"],"msg":"Field required","input":null,"url":"https://errors.pydantic.dev/2.1/v/missing"}]}
# likeadmin环境
# 422
# {"detail":[{"loc":["body","name"],"msg":"field required","type":"value_error.missing"},{"loc":["body","price"],"msg":"field required","type":"value_error.missing"}]}
# 200
# {"item_id":7,"item":{"name":"Foo","description":"The pretender","price":42.0,"tax":3.2}}

bug 3

Header 参数 - FastAPI (tiangolo.com)中"声明 Header 参数"处(还有Cookie 参数 - FastAPI (tiangolo.com)中"声明 Cookie 参数"处),选python3.6,接口示例代码是

from typing import Unionfrom fastapi import FastAPI, Header
from typing_extensions import Annotatedapp = FastAPI()@app.get("/items/")
async def read_items(user_agent: Annotated[Union[str, None], Header()] = None):return {"User-Agent": user_agent}
from typing import Unionfrom fastapi import Cookie, FastAPI
from typing_extensions import Annotatedapp = FastAPI()@app.get("/items/")
async def read_items(ads_id: Annotated[Union[str, None], Cookie()] = None):return {"ads_id": ads_id}

 我实际写的接口代码是

from typing import Unionfrom fastapi import FastAPI, Header, Cookie
from typing_extensions import Annotatedapp = FastAPI()@app.get("/items/")
async def read_items(BIDUPSID: Annotated[Union[str, None], Cookie()] = None,  # 从请求头的cookie中获取键为BIDUPSID的值PSTM: Annotated[Union[str, None], Cookie()] = None,BA_HECTOR: Annotated[Union[str, None], Cookie()] = None,user_agent: Annotated[Union[str, None], Header()] = None  # fastapi自动将user_agent转为user-agent,又因HTTP headers是大小写不敏感的,所以user_agent就是User-Agent。from https://fastapi.tiangolo.com/zh/tutorial/header-params/#_1中"自动转换处"):return {"Cookie": f'BIDUPSID={BIDUPSID}; PSTM={PSTM}; BA_HECTOR={BA_HECTOR}', "User-Agent": user_agent}'''
# from https://fastapi.tiangolo.com/zh/tutorial/header-params/#_1中"自动转换处"
自动转换
Header 在 Path, Query 和 Cookie 提供的功能之上有一点额外的功能。大多数标准的headers用 "连字符" 分隔,也称为 "减号" (-)。但是像 user-agent 这样的变量在Python中是无效的。因此, 默认情况下, Header 将把参数名称的字符从下划线 (_) 转换为连字符 (-) 来提取并记录 headers.同时,HTTP headers 是大小写不敏感的,因此,因此可以使用标准Python样式(也称为 "snake_case")声明它们。因此,您可以像通常在Python代码中那样使用 user_agent ,而不需要将首字母大写为 User_Agent 或类似的东西。如果出于某些原因,你需要禁用下划线到连字符的自动转换,设置Header的参数 convert_underscores 为 False
'''

我写的请求代码是

import requestsurl = 'http://127.0.0.1:8000/items/'
headers = {'Cookie': 'BIDUPSID=A9DA10BEC1294DD8D4F6E654A52CBDC8; PSTM=1691732828; BAIDUID=A9DA10BEC1294DD8402C67E5E8156634:FG=1; BD_UPN=12314753; BA_HECTOR=8h8k05052l000la0a1810h0j1idbjgf1p; BAIDUID_BFESS=A9DA10BEC1294DD8402C67E5E8156634:FG=1; BD_CK_SAM=1; PSINO=2; ZFY=FJzChFI0tlXn0pdMbu9GDJzHS1iNKW8:A:AjdKkCxk2W0:C; delPer=0; BD_HOME=1; COOKIE_SESSION=21_0_0_0_3_0_0_0_0_0_0_0_23_0_4_0_1691734574_0_1691734570%7C2%230_0_1691734570%7C1; H_PS_PSSID=36546_39112_38831_39008_39114_39038_38917_26350_39138_39132_39137_22157_39100; H_PS_645EC=d157JRTS54%2FnnbXzJd5jNKP%2FMviUleulBfUEwB4MIKKEUrwiHAKJcjpnt4A','Referer': 'https://www.baidu.com/','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203'
}
# cookie = {
#     'BIDUPSID': 'A9DA10BEC1294DD8D4F6E654A52CBDC8',
#     'PSTM': '1691732828',
#     'BA_HECTOR': '8h8k05052l000la0a1810h0j1idbjgf1p'
# }response = requests.get(url=url, headers=headers)
# response = requests.get(url=url, headers=headers, cookies=cookie)  # 注释掉headers中Cookie,取消cookie的注释,再用这个请求,和上一行的结果一样
print(response.status_code)
print(response.text)

 likeadmin的环境获取不到Cookie和User-Agent;纯fastapi环境,Cookie和User-Agent都能获取。 

# likeadmin的环境的结果
{"Cookie":"BIDUPSID=None; PSTM=None; BA_HECTOR=None","User-Agent":null}# 纯fastapi环境的结果
{"Cookie":"BIDUPSID=A9DA10BEC1294DD8D4F6E654A52CBDC8; PSTM=1691732828; BA_HECTOR=8h8k05052l000la0a1810h0j1idbjgf1p","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203"}

bug 4

路径操作配置 - FastAPI (tiangolo.com)中"status_code状态码"处,接口示例代码是

from typing import Set, Unionfrom fastapi import FastAPI, status
from pydantic import BaseModelapp = FastAPI()class Item(BaseModel):name: strdescription: Union[str, None] = Noneprice: floattax: Union[float, None] = Nonetags: Set[str] = set()@app.post("/items/", response_model=Item, status_code=status.HTTP_201_CREATED)  # 也可以直接用status_code=201
async def create_item(item: Item):return item

我写的请求代码是

import requestsurl = 'http://127.0.0.1:8000/items/'
form_data = {'name': 'Bob','price': 12.3,
}
response = requests.post(url=url, json=form_data)
print(response.status_code)
print(response.text)

 likeadmin的环境打印的状态码还是200,没变成设置的201;纯fastapi环境的是201。

bug 1 与 bug 2 与 bug 3 与 bug 4的解决

既然两个虚拟环境的python版本一样,忽然想到是不是fastapi版本不一样导致的,查看纯fastapi环境(2023年8月11日)得到

Package              Version
-------------------- -----------
annotated-types      0.5.0
anyio                3.7.1
certifi              2023.7.22
click                8.1.6
colorama             0.4.6
dnspython            2.4.2
email-validator      2.0.0.post2
exceptiongroup       1.1.2
fastapi              0.101.0
h11                  0.14.0
httpcore             0.17.3
httptools            0.6.0
httpx                0.24.1
idna                 3.4
itsdangerous         2.1.2
Jinja2               3.1.2
MarkupSafe           2.1.3
orjson               3.9.4
pip                  23.2.1
pydantic             2.1.1
pydantic_core        2.4.0
pydantic-extra-types 2.0.0
pydantic-settings    2.0.2
python-dotenv        1.0.0
python-multipart     0.0.6
PyYAML               6.0.1
setuptools           68.0.0
sniffio              1.3.0
starlette            0.27.0
typing_extensions    4.7.1
ujson                5.8.0
uvicorn              0.23.2
watchfiles           0.19.0
websockets           11.0.3
wheel                0.38.4

将likeadmin的fastapi库由0.85.0升级到和纯fastapi环境一样的0.101.0,再运行上面的示例代码,就能得到正确的结果了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/90541.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot中配置文件介绍及其使用教程

目录 一、配置文件介绍 二、配置简单数据 三、配置对象数据 四、配置集合数据 五、读取配置文件数据 六、占位符的使用 一、配置文件介绍 SpringBoot项目中,大部分配置都有默认值,但如果想替换默认配置的话,就可以使用application.prop…

从零手搓一个【消息队列】项目设计、需求分析、模块划分、目录结构

文章目录 一、需求分析1, 项目简介2, BrokerServer 核心概念3, BrokerServer 提供的核心 API4, 交换机类型5, 持久化存储6, 网络通信7, TCP 连接的复用8, 需求分析小结 二、模块划分三、目录结构 提示:是正在努力进步的小菜鸟一只,如有大佬发现文章欠佳之…

阿里云效自动构建python自动测试脚本

之前一直用的是jenkins自动构建自动化脚本,因为现在的公司统一在阿里云效的流水线上做代码的管理,构建,要求自动化测试也在上面自动构建,故而学习了一下。为自己做一个记录,也给有需要的朋友做一个参考。 1. 新建流水…

设计模式4、建造者模式 Builder

解释说明:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 UML 结构图: 抽象建造者(Builder):这个接口规定要实现复杂对象的那些部分的创建,并不设计具体部件对象的创…

在MySQL中使用VARCHAR字段进行日期筛选

🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁 🦄 博客首页——🐅🐾猫头虎的博客🎐 🐳 《面试题大全专栏》 🦕 文章图文…

ROS2 从头开始​​:第6部分 - ROS2 中的 DDS,用于可靠的机器人通信

一、说明 在这篇文章中,我们将重点关注 ROS 2的通信栈DDS,其中这是介于管理节点通信与控制节点通信环节,是上位机决策体系与下位机的控制体系实现指令-执行-反馈的关键实现机制。 二、ROS工程的概念框架 现代机器人系统非常复杂,因为需要集成各种类型的传感器、执行器和其…

No148.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

MySQL到TiDB:Hive Metastore横向扩展之路

作者:vivo 互联网大数据团队 - Wang Zhiwen 本文介绍了vivo在大数据元数据服务横向扩展道路上的探索历程,由实际面临的问题出发,对当前主流的横向扩展方案进行了调研及对比测试,通过多方面对比数据择优选择TiDB方案。其次分享了整…

查看react内置webpack版本的方法

yarn list --pattern webpack npm ls --pattern webpack

Python3操作SQLite3创建表主键自增长|CRUD基本操作

Win11查看安装的Python路径及安装的库 Python PEP8 代码规范常见问题及解决方案 Python3操作MySQL8.XX创建表|CRUD基本操作 Python3操作SQLite3创建表主键自增长|CRUD基本操作 anaconda3最新版安装|使用详情|Error: Please select a valid Python interpreter Python函数绘…

Docker版部署RocketMQ开启ACL验证

一、拉取镜像 docker pull apache/rocketmq:latest 二、准备挂载目录 mkdir /usr/local/rocketmq/data mkdir /usr/local/rocketmq/conf 三、运行 docker run \ -d \ -p 9876:9876 \ -v /usr/local/rocketmq/data/logs:/home/rocketmq/logs \ -v /usr/local/rocketmq/data…

十五.镜头知识之景深(Depth of Field)

十五.镜头知识之景深(Depth of Field) 文章目录 十五.镜头知识之景深(Depth of Field)15.1 概述15.2 景深(depth of field)定义15.3 景深原理15.3.1 弥散圆(circle of confusion) 15.4 景深总结 15.1 概述 先看两个例子,拍摄花、昆虫等照片时,背景拍的比…

【C++】vector的介绍 | 常见接口的使用

目录 vector的介绍 常见接口 构造函数 尾插push_back() vector的遍历 1.用方括号下标 遍历: 2.调用at()来访问: 3.用迭代器遍历: 4.范围for遍历: vector空间 vector增删查改 覆盖assign() 查找find() 插入insert() …

【加载数据--自定义自己的Dataset类】

【加载数据自定义自己的Dataset类】 1 加载数据2 数据转换3 自定义Dataset类4 划分训练集和测试集5 提取一批次数据并绘制样例图 假设有四种天气图片数据全部存放与一个文件夹中,如下图所示: ├─dataset2 │ cloudy1.jpg │ cloudy10.jpg │ …

物联网、工业大数据平台 TDengine 与苍穹地理信息平台完成兼容互认证

当前,在政府、军事、城市规划、自然资源管理等领域,企业对地理信息的需求迅速增加,人们需要更有效地管理和分析地理数据,以进行决策和规划。在此背景下,“GIS 基础平台”应运而生,它通常指的是一个地理信息…

FL Studio21.1电脑试用体验版音乐制作软件

我一直以来对音乐艺术都很感兴趣。最近我接触到了一款名为 FL Studio 的电脑版音乐制作软件,深感其强大功能和广泛适用性。通过使用这款软件,我不仅深入了解了音乐制作的过程与技巧,也加深了对音乐创作的理解。 FL Studio 最初是一款针对 MI…

四川玖璨电子商务有限公司抖音培训引领电商新潮

近年来,随着电子商务的迅猛发展,抖音这个社交媒体平台也逐渐成为了商家必争之地。四川玖璨电子商务有限公司抖音培训,为你解锁电商流量密码,助你一飞冲天! 一、抖音电商:下一个电商蓝海 作为拥有海量用户的…

爬虫抓取数据时显示超时,是爬虫IP质量问题?

当我们进行网络爬虫开发时,有时会遇到抓取数据时出现超时的情况。这可能是由于目标网站对频繁请求做了限制,或者是由于网络环境不稳定造成的。其中,爬虫IP的质量也是导致超时的一个重要因素。本文将探讨抓取数据时出现超时的原因,…

前端开发 vs. 后端开发:编程之路的选择

文章目录 前端开发:用户界面的创造者1. HTML/CSS/JavaScript:2. 用户体验设计:3. 响应式设计:4. 前端框架: 后端开发:数据和逻辑的构建者1. 服务器端编程:2. 数据库:3. 安全性&#…

深度学习入门教学——对抗攻击和防御

目录 一、对抗样本 二、对抗攻击 三、对抗防御 一、对抗样本 对抗样本是指对机器学习模型的输入做微小的故意扰动,导致模型输出结果出现错误的样本。深度神经网络在经过大量数据训练后,可以实现非常复杂的功能。在语音识别、图像识别、自然语言处理等任务上被广…