fastAPI教程:路由操作及HTTP请求响应

FastAPI

三、路由操作

3.1 路由装饰器

路由装饰器,也叫路径操作装饰器。

FastAPI提供了一系列基于HTTP请求作为方法名的装饰器给开发者用于绑定url地址提供给外界操作API接口。

HTTP方法FastAPI代码描述
GET@app.get()
async 方法名():
pass
获取数据
POST@app.post()
async 方法名():
pass
添加数据
PUT@app.put()
async 方法名():
pass
更新数据[全部]
PATCH@app.patch()
async 方法名():
pass
更新数据[部分]
DELETE@app.delete()
async 方法名():
pass
删除数据
多个操作@app.api_router()
async 方法名():
pass
OPTIONS@app.options()
async 方法名():
pass
获取当前资源所支持的通信选项
HEAD@app.head()
async 方法名():
pass
获取资源的元数据,如文件的大小、修改时间等
# 1. 导入核心模块
from fastapi import FastAPI# 2. 创建web应用程序的实例对象
app = FastAPI()# 3. 创建API接口,提供给外界使用
@app.get("/")
async def get_student():"""获取学生数据"""return {"method": "get", "name": "获取学生数据"}@app.post("/", status_code=201)
async def add_student():"""添加学生数据"""return {"method": "post", "name": "添加学生数据"}@app.put("/", status_code=201)
async def edit_student():"""修改学生数据[全部]"""return {"method": "put", "name": "修改学生数据[全部]"}@app.patch("/", status_code=201)
async def update_student():"""修改学生数据[部分]"""return {"method": "patch", "name": "修改学生数据[部分]"}@app.delete("/", status_code=204)
async def del_student():"""删除学生数据"""return@app.api_route("/more.html", methods=['GET', 'POST'], status_code=200)
async def more_student():"""对学生数据进行多种请求操作"""return {"method": "more", "name": "对学生数据进行多种请求操作"}if __name__ == '__main__':# 5. 启动项目import uvicorn# uvicorn.run("访问入口的模块名:实例对象", host="0.0.0.0", port=端口, reload=True)uvicorn.run("main:app", host="0.0.0.0", reload=True)

访问接口文档:http://127.0.0.1:8000/docs,效果如下:

在这里插入图片描述

在开发中多数情况下,建议大家使用postman或者apifox这样的工具进行接口的访问,方便调测。

在这里插入图片描述

【扩展】路由(路径操作)装饰器的具体参数
@app.get("/students/{id}",  # 访问路径,访问时必须左边加上域名/IP+端口response_model=Item,  # 响应数据的格式与类型,Item是开发者自定义的一个pydantic风格的JSON对象,后面再详细学习status_code=status.HTTP_200_OK, # 状态码,status是fastapi提供给开发者使用的一个状态码别名模块,让响应状态码的数字更加清晰易懂tags=["Student"],  # 标签,对API接口在接口文档中进行归纳分类用的。summary="this is summary", # 摘要,对API接口在接口文档中进行说明补充的摘要标题description="this is description",  # 详细描述,对API接口在接口文档中进行详细说明当前接口的使用和用途的response_description= "this is response_description",deprecated=False,
)

main.py,代码:

# 1. 导入核心模块
from fastapi import FastAPI
from pydantic import BaseModel
from fastapi import status# 2. 创建web应用程序的实例对象
app = FastAPI()# pydantic风格的json对象
class Student(BaseModel):# 属性名:数据类型name: strage: int# 3. 创建API接口,提供给外界使用
@app.get(path="/",status_code=status.HTTP_201_CREATED,response_model=Student,tags=["Student"],summary="接口的简要说明[摘要标题]",description="接口的详细说明,例如对参数和返回结果进行详细说明和补充的",response_description="对接口的返回结果进行详细说明的",# deprecated 表示当前接口是否属于废弃不适用的,主要出现一个年老失修的项目中,旧的代码继续使用当前接口,但是新的代码不再推荐使用这个接口,此时旧需要进行标记了。deprecated=True,
)
async def get_student():"""获取学生数据"""return {"name": "小明", "age": 17}if __name__ == '__main__':# 5. 启动项目import uvicorn# uvicorn.run("访问入口的模块名:实例对象", host="0.0.0.0", port=端口, reload=True)uvicorn.run("main:app", host="0.0.0.0", reload=True)

访问接口文档的效果如下:

在这里插入图片描述

3.2 路由分组

FastAPI提供了include_router功能,允许开发者分目录分模块进行路由绑定,在大型项目中接口数量多了就会容易重现路径重复的情况,所以分目录下来区分不同的功能,对开发者编写API接口更加友好。

在这里插入图片描述

目录结构:

项目目录/
├── apps/  # 应用存储目录,主要分目录区分不同的功能和不同的业务
│   ├── goods/  # 举例的应用代码目录,例如goods表示商品相关的功能
│   │   ├── api.py  # api接口代码文件
│   │   └── __init__.py 
│   ├── __init__.py
│   └── users/   # 举例的应用代码目录,例如goods表示用户相关的功能
│       ├── api.py # api接口代码文件
│       └── __init__.py
└── main.py     # fastAPI项目的入口启动程序,需要通过当前文件运行项目才行,上面所有的文件不能直接运行,而是导包到main.py里面去运行和访问。

项目目录/main.py,项目入口文件,代码:

import uvicornfrom fastapi import FastAPI# 导入用户相关功能
from apps.users.api import router as user_router
# 导入商品相关功能
from apps.goods.api import router as goods_router
app = FastAPI()
# 把用户相关的分组路由注册(绑定)到FastAPI的总路由app.routes
app.include_router(user_router, prefix="/user")
app.include_router(goods_router, prefix="/goods")@app.get("/")
def home():return "web站点的首页"if __name__ == '__main__':uvicorn.run("main:app", port=8000, host="0.0.0.0", reload=True)

项目目录/apps/goods/api.py,代码:

"""商品功能(模块)"""
# 导入路由类
from fastapi import APIRouter# 创建一个分组路由对象
router = APIRouter()@router.get("/goods")
async def list():"""获取商品列表"""return {"method": "get", "name":"获取商品列表"}@router.post("/goods")
async def create():"""添加商品"""return {"method": "post", "name":"添加商品数据"}

项目目录/apps/user/api.py,代码:

"""用户相关功能[模块]"""
from fastapi import APIRouter# 创建一个分组路由对象
router = APIRouter()# 把当前接口注册/绑定到当前分组路由对象
@router.post("/login")
async def login():"""用户登录功能"""return {"method": "post", "name":"用户登录"}@router.post("/register")
async def register():"""用户注册功能"""return {"method": "post", "name":"用户注册"}

最终通过postman,访问接口,如果能正常响应数据则表示路由分组成功。

添加商品:POST http://127.0.0.1:8000/goods/goods

商品列表:GET http://127.0.0.1:8000/goods/goods

用户登录:POST http://127.0.0.1:8000/user/login

用户注册:POST http://127.0.0.1:8000/user/register

路由分组后的API接口的完整访问路径 = 前缀(prefix)+ 路径(path)

在这里插入图片描述

四、HTTP请求响应

4.1 请求操作

请求(request),是FastAPI提供给开发者用于通过各种方式接收来自客户端的请求数据【请求行、请求头、请求体】。

4.1.1 接收请求行数据

在客户端发送请求,用户是可以通过路径参数、查询查看来把请求参数(变量数据)发送到服务端。服务端可以通过fastAPI提供的对应方式来进行接收。

4.1.1.1 路径参数

路径参数,指代在请求行中的路径中使用部分路径作为参数,可以让客户端把相关参数作为路径发送给服务端的接口函数/类中。

路径参数的基本使用

以使用与 Python 格式化字符串相同的语法来声明路径"参数"或"变量"。main.py,代码:

import uvicorn
from fastapi import FastAPIapp = FastAPI()"""接收单个路径参数"""
@app.get("/user/{user_id}")
async def index(user_id):return {"id": user_id, "name": "xiaoming", "age": 17}"""接收多个路径参数[基于命名绑定的,所以接口函数中的参数名,先后顺序不重要,但是参数名必须要一一对应,不能遗漏]"""
@app.get("/stock/{company}/{stock_date}")
async def index(company, stock_date):return {"公司": company, "股票日期": stock_date}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

路径参数 user_id 的值将作为参数 user_id 传递给接口函数/接口类方法。

http://127.0.0.1:8000/user/1000,访问效果:

在这里插入图片描述

http://127.0.0.1:8000/stock/天银机电/2024-10-01,访问效果:

在这里插入图片描述

路径参数限定类型

你可以使用标准的 Python 类型标注为函数中的路径参数限定当前参数的数据类型。

main.py,代码:

import uvicorn
from fastapi import FastAPIapp = FastAPI()"""接收单个路径参数"""
@app.get("/user/{user_id}")
async def index(user_id: int):return {"id": user_id, "name": "xiaoming", "age": 17}"""接收多个路径参数[基于命名绑定的,所以接口函数中的参数名,先后顺序不重要,但是参数名必须要一一对应,不能遗漏]"""
@app.get("/stock/{company}/{stock_date}/{boo}")
async def index(company: str, stock_date: str, boo: bool):return {"公司": company, "股票日期": stock_date, "boo": boo}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

在这个例子中,user_id 被声明为 int 类型。这将为你的函数提供编辑器支持,包括错误检查、代码补全等等。

访问:http://127.0.0.1:8000/stock/%E5%A4%A9%E9%93%B6%E6%9C%BA%E7%94%B5/2233/1

路径参数的匹配问题

因为fastAPI的路由内部,会接收客户端(浏览器/postman)发送过来的请求报文[字符串格式]->在请求处理过程中,会对客户端请求的路径进行正则匹配,匹配成功则执行对应路由的接口函数。所以,当有部分接口函数如果出现部分路径重叠,则建议调整路径,否则容易出现匹配覆盖的问题,导致后面的接口函数永远无法被访问了。

比如 /data/all,我们假设它用来获取所有公司的股票信息的,然后还使用路径 /data/{company} 来通过公司名获取关于指定公司的股票数据。

由于路由的匹配操作是按顺序依次运行的,你需要确保路径 /data/all 声明在路径 /data/{company}之前,main.py,代码:

import uvicorn
from fastapi import FastAPIapp = FastAPI()@app.get("/data/{company}")
async def index(company: str):"""查询指定公司的信息"""return {"指定公司名": company}@app.get("/data/all") # 这个接口这辈子都无法被访问了。
async def index():"""查询所有公司的数据"""return {"所有公司": "所有公司的数据"}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

否则,/user/{username} 的路径还将与 /user/me 相匹配,"认为"自己正在接收一个值为 "me"username 参数。

4.1.1.2 查询参数

查询参数(Search Params,或者叫Query String),就是 url? 之后用&分割的 key-value 键值对参数,FastAPI提供的请求操作也支持获取查询参数的。main.py,代码:

import uvicorn
from fastapi import FastAPI, Queryapp = FastAPI()@app.get("/data/{company}")
async def index(company: str, dm: int, user: str):"""查询指定公司的信息"""return {"指定公司名": company, "股票代码": dm, "企业法人": user}@app.get("/data/list")
async def index(comps: list=Query(title="公司列表")):"""查询多个公司的相关信息测试访问地址:http://127.0.0.1:8000/data/list?comps=A&comps=B&comps=C"""return company  # ["A", "B", "C"]if __name__ == '__main__':uvicorn.run("main:app", reload=True)

上面代码中,dmuser不在路径参数中,就表示当前两个参数属于查询参数了。http://127.0.0.1:8000/data/天银机电?dm=123456&user=root,访问效果:

在这里插入图片描述

练习:

声明一个接口,提供给外界访问。
url path:/stock
queryString: dm=302022&fs=5m
return 对应的公司的历史交易数据

练习代码:

import uvicorn
from fastapi import FastAPI
import requests, jsonapp = FastAPI()licence = "bb745717391d449aed""""
练习:声明一个接口,提供给外界访问,
path:/stock
queryString: dm=302022&fs=5m
return 对应的公司的历史交易数据
"""@app.get("/stock")
async def index(dm: int, fs: str):"""查询指定公司的历史分时交易数据"""response = requests.get(f"http://api.biyingapi.com/hszbl/fsjy/{dm}/{fs}/{licence}")data = json.loads(response.content)return dataif __name__ == '__main__':uvicorn.run("main:app", reload=True)
4.1.1.3 查询参数的默认值和可选类型参数

main.py,代码:

import uvicorn
from typing import Union
from fastapi import FastAPIapp = FastAPI()@app.get("/stock/{dm}")
async def main(dm: str, dt: str, options: Union[int, bool] = None, fs: str="5m"):""":param dm: 路径参数,必填的参数:param fs: 查询参数,有默认值的可选参数,客户端不传值会采用默认值:param dt: 查询参数,必填的参数:param options: 查询参数,可选类型的参数,即可以传递整数,也可以传递布尔值,FastAPI会内部自动转换参数的数据类型。:return:"""return {"dm": dm, "fs": fs, "dt": dt, "options": options}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

扩展:

在python3.6新增了类型标注typing用于标记变量、参数的数据类型以后,在python3.10版本又进一步把python3.6提供的typing.Union改进 | 语法了。

所以如果是python>=3.10版本的时候,可选参数类型的写法如下:

import uvicorn
from typing import Union
from fastapi import FastAPIapp = FastAPI()@app.get("/stock/{dm}")
async def main(dm: str, dt: str, options: int | bool = None, fs: str="5m"):""":param dm: 路径参数,必填的参数:param fs: 查询参数,有默认值的可选参数,客户端不传值会采用默认值:param dt: 查询参数,必填的参数:param options: 查询参数,可选类型的参数,即可以传递整数,也可以传递布尔值,FastAPI会内部自动转换参数的数据类型。:return:"""return {"dm": dm, "fs": fs, "dt": dt, "options": options}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

大家可以根据以下命令创建一个新的虚拟环境进行测试。终端命令如下:

# 先查看自己是否曾经创建过python>=3.10
conda env list
# 如果没有python>=3.10
conda create -n py310  python=3.10
# 接下来,安装好fastapi和uvicorn模块,可以在pycharm中切换虚拟环境运行上面的代码。
!!!切记,后面要换回自己常用的环境。
4.1.1.3 参数的验证

大部分公司不会使用这种验证手段,但不排除少数公司使用了,所以我们简单了解下。

fastAPI提供了2个对象PathQuery,分别用于验证路径参数和查询参数的内容和错误提示。PathQuery使用上一模一样。

Path对象验证路径参数

main.py,代码:

import uvicorn
from fastapi import FastAPI, Pathapp = FastAPI()"""
参数名: str = Path(title="请输入路径参数", pattern="\d{6}", min_length=6, max_length=6)
参数名: int = Path(title="请输入ID参数", le=999, lt=1000, ge=0, gt=-1)
title: 参数提示,用于提供给api接口文档
pattern: 在参数格式如果是str,则按正则进行规则匹配
min_length: 在参数格式如果是str,则按最小长度进行判断
max_length: 在参数格式如果是str,则按最大长度进行判断
le=999:在参数格式如果是int,float,则值必须小于或等于999
lt=1000: 在参数格式如果是int,float,则值必须小于1000
ge=0: 在参数格式如果是int,float,则值必须大于或等于0
gt=-1: 在参数格式如果是int,float,则值必须大于-1
"""
@app.get("/stock/{dm}")
async def index(dm: str = Path(title="请输入路径参数dm", pattern="\d{6}", min_length=6, max_length=6)):return {"dm": dm}if __name__ == '__main__':uvicorn.run("main:app", reload=True)
Query对象验证查询参数

main.py,代码:

import uvicorn
from fastapi import FastAPI, Queryapp = FastAPI()"""
参数名: str = Query(title="请输入路径参数", pattern="\d{6}", min_length=6, max_length=6)
参数名: int = Query(title="请输入ID参数", le=999, lt=1000, ge=0, gt=-1)
title: 参数提示,用于提供给api接口文档
pattern: 在参数格式如果是str,则按正则进行规则匹配
min_length: 在参数格式如果是str,则按最小长度进行判断
max_length: 在参数格式如果是str,则按最大长度进行判断
le=999:在参数格式如果是int,float,则值必须小于或等于999
lt=1000: 在参数格式如果是int,float,则值必须小于1000
ge=0: 在参数格式如果是int,float,则值必须大于或等于0
gt=-1: 在参数格式如果是int,float,则值必须大于-1
"""
fs_query = Query(title="请输入分时参数", pattern="(5m|30m|15m|60m)", min_length=2, max_length=3)
@app.get("/stock/{dm}")
async def index(dm: str, fs: str = fs_query):return {"dm": dm}if __name__ == '__main__':uvicorn.run("main:app", reload=True)
4.1.2 接收请求头数据

fastAPI提供了Header对象,允许开发人员在接口函数/接口类方法方法中,提取客户端HTTP请求头的相关数据。main.py,代码:

import uvicorn
from fastapi import FastAPI, Headerapp = FastAPI()@app.get("/stock")
async def index(user_agent: str = Header(),accept: str= Header(),content_type: str= Header(default="text/html"),host: str = Header(),auth_token: str = Header(),):""":param user_agent: 对应HTTP请求中的 user-agent:return:"""return {# httpBI标准请求头"user_agent": user_agent,"accept": accept,"content_type": content_type,"host": host,# 用户的自定义请求头数据"auth_token": auth_token}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

postman中发送HTTP请求可以自定义请求头,代码:

在这里插入图片描述

补充:

HTTP协议本身有提供了一些内置的请求头,格式都是按单词首字母大小,多个单词使用-拼接的。如果我们要自定义请求头,尽量仿照HTTP协议的内置请求头进行编写。

例如,自定义请求头推荐如下:

auth-tokenAuth-Token,都可以。

accessAccess,都可以。

在FastAPI中,接收上面自定义的请求头时,参数名必须按单词小写的格式,多次单词使用_拼接进行接收。

auth_token

access

4.1.3 接收请求体数据

当你需要将数据从客户端(例如:浏览器,ajax,postman)发送给 API接口函数/接口类方法时,你将其作为「请求体」发送即可。

对于 API接口要来自客户端的数据,必须进行验证。因此FastAPI 基于 PydanticPydantic 就可以用来对接收的请求体数据进行类型强制检查(校验数据)。不符合类型要求就可以抛出异常信息返回给客户端。

FastAPI支持对接收数据进行类型强制检查(校验数据)这个功能,对于在服务端提供API接口非常有用,会让服务端代码更加健壮,也会加快开发人员开发项目的速度,因此有了 Pydantic,FastAPI的开发者就不再需要自己写一行一行的做类型检查。

pydantic在我们安装FastAPI的时候已经默认顺便一起安装了的。所以开发者直接使用pydantic即可。

请求体数据只有在客户端发送postputpatch请求的时候才有。

4.1.3.1 接收JSON数据

main.py,代码:

import uvicorn
from fastapi import FastAPI
from pydantic import BaseModelapp = FastAPI()# pypantic风格的数据模型对象,对象必须直接或间接继承 pypantic.BaseModel对象
class User(BaseModel):username: strpassword: str@app.post("/login")
async def login(user: User): # 控制反转(依赖注入):根据类型直接对数据实例化并注入函数的参数中return {"username": user.username, "password": user.password}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

使用postman发送json请求体数据:

在这里插入图片描述

在这里插入图片描述

接收复杂结构的JSON数据

main.py,代码:

import uvicorn
from fastapi import FastAPI, Body
from pydantic import BaseModelapp = FastAPI()# pypantic风格的验证数据对象,对象必须直接或间接继承 pypantic.BaseModel对象
class User(BaseModel):username: strpassword: strclass Goods(BaseModel):title: strprice: float# fastAPI提供了Body对象给我们接收客户端发送过来的JSON中的单个参数值
@app.post("/login")
async def login(user: User, goods: Goods, remember: bool = Body()):return {"username": user.username,"password": user.password,"remember": remember,"goods": goods}if __name__ == '__main__':uvicorn.run("main:app", reload=True)

postman发送JSON数据,效果如下:

在这里插入图片描述

模型数据BaseModel的底层原理是基于type元类来完成

main.py,代码:


"""了解BaseModel的底层,有利于将来对FastAPI更深层的了解"""
# # 模型对象[声明数据的结构和属性的类型]
# from pydantic import BaseModel
# class User(BaseModel):
#     username: str
#     password: str
#
# if __name__ == '__main__':
#     data = {"username": "xiaoming", "password": "123456"}
#     user = User(**data) # user = User(username="xiaoming", password="123456")
#
#     print(user, type(user))
#     print(user.username, user.password)class BaseTypeClass(type):def __call__(self, *args, **kwargs):# print(self)  # 被当成函数执行的那个类cls_attrs = self.__dict__['__annotations__']# 格式验证self.validator(cls_attrs, kwargs)# 通过元类创建数据对象return type(self.__name__, (object,), {**kwargs,'__init__': self.init,})def validator(self, cls_attrs, kwargs):"""通过循环判断数据格式问题:param cls_attrs: 当前类属性和格式要求:param kwargs: 客户端的数据:return:"""print(cls_attrs)for key, value in kwargs.items():if not isinstance(value, cls_attrs[key]):raise Exception(f"{key}参数的格式不正确,必须是{cls_attrs[key]}类型数据")def init(self, *args, **kwargs):for key, value in kwargs.items():setattr(self, key, value)class BaseModel(metaclass=BaseTypeClass):passclass User(BaseModel):username: strpassword: strif __name__ == '__main__':data = {"username": "xiaoming", "password": "123456"}user = User(**data)  # user = User(username="xiaoming", password="123456")print(">>>>>", user.username)print(">>>>>", user.password)
4.1.3.2 验证客户端请求数据

pydantic针对于客户端数据不仅提供了接收功能,还提供了Field对象允许我们像BodyPathQuery那样对数据进行具体的验证。

1. 基于pydantic对数据进行接收,并对数据类型进行基本验证

文档:https://docs.pydantic.dev/latest/concepts/models/#error-handling

main.py,代码:

from pydantic import BaseModel# 模型对象[声明数据的结构和属性的类型]
class User(BaseModel):username: strpassword: strif __name__ == '__main__':data = {"username": "xiaoming", "password": "123456"}user = User(**data) # user = User(username="xiaoming", password="123456")print(user, type(user))print(user.username, user.password)
2. 基于pydantic提供Field进行进行数据校验

在旧版本pydantic中提供的类叫Schema,新版本pydantic:2.x改名为Field

文档:https://docs.pydantic.dev/latest/api/fields/#pydantic.fields.Field

Field类是pydantic提供给开发者在数据模型中对字段声明验证规则的工具类。用法类似于BodyQueryPath等类,所以也具有max_lengthmin_lengthltlegtgepatterndefault等属性。

main.py,代码:

"""基于pydantic提供Field进行进行数据校验"""
from pydantic import BaseModel, Field, ValidationErrorclass User(BaseModel):username: str = Field(min_length=3, max_length=16)password: str = Field(min_length=6, max_length=16)mobile: str = Field(pattern="^1[3-9]\d{9}$")if __name__ == '__main__':# 1. BaseModel提供了接收客户端数据,并返回模型对象的功能# data = {"username": "xiaoming", "password": "123456"}# user = User(**data) # user = User(username="xiaoming", password="123456")## print(user, type(user))# print(user.username, user.password)# 2. pypantic还可以Field允许我们针对单个数据属性(字段)进行独立的验证try:# data = {"username": "xm", "password": "123"}# data = {"username": "xiaoming", "password": "123456", "mobile": "10086"}data = {"username": "xiaoming", "password": "123456", "mobile": "13312345678"}user = User(**data)print(user)except ValidationError as e:print(e.json())
3. 基于pydantic提供的field_validator方法进行数据校验

在旧版本的pydantic中使用的validator来验证数据,在新版本的pydantic:2.x已经更新为field_validatormodel_validator

验证单个数据字段

文档:https://docs.pydantic.dev/latest/api/functional_validators/#pydantic.functional_validators.field_validator

main.py,代码:

from pydantic import BaseModel, Field, ValidationError, field_validator# 已经注册用户
user_list = ["root", "admin"]class User(BaseModel):username: str = Field(title="用户名", min_length=3, max_length=16)password: str = Field(title="登录密码", min_length=6, max_length=16)mobile: str = Field(title="手机号", pattern="1[3-9]\d{9}")password2: str = Field(title="确认密码", min_length=6, max_length=16)"""使用pydantic提供field_validator对单个数据进行复杂验证"""@field_validator("username")def check_username(cls, data):"""验证数据失败,可以通过 assert 抛出异常"""# assert 代表期望,期待,相当于if 判断# assert 表达式 提示文本# 当表达式的结果为False时,则把提示文本 通过异常的方式进行处理# assert username not in user_list, "当前用户已经注册了!""""验证数据失败,也可以通过ValueError抛出异常"""if username in user_list:raise ValueError("当前用户已经注册了!")# 必须有数据返回,否则该数据就丢失了。return usernameif __name__ == '__main__':data = {"username": "admin", "mobile": "13312345678", "password": "123456", "password2": "12345678"}try:user = User(**data)except ValidationError as e:print(e.json())

验证多个数据字段

文档:https://docs.pydantic.dev/latest/api/functional_validators/#pydantic.functional_validators.model_validator

main.py,代码:

from pydantic import BaseModel, Field, ValidationError, field_validator, model_validator# 已经注册用户
user_list = ["root", "admin"]class User(BaseModel):username: str = Field(title="用户名", min_length=3, max_length=16)password: str = Field(title="登录密码", min_length=6, max_length=16)mobile: str = Field(title="手机号", pattern="1[3-9]\d{9}")password2: str = Field(title="确认密码", min_length=6, max_length=16)"""使用pydantic提供field_validator对单个数据进行复杂验证"""@field_validator("username")@classmethod # 要么不要写,写的话,则必须写在field_validator的下方,def check_username(cls, username):"""验证数据失败,可以通过 assert 抛出异常"""# assert 代表期望,期待,相当于if 判断# assert 表达式 提示文本# 当表达式的结果为False时,则把提示文本 通过异常的方式进行处理# assert username not in user_list, "当前用户已经注册了!""""验证数据失败,也可以通过ValueError抛出异常"""if username in user_list:raise ValueError("当前用户已经注册了!")# 必须有数据返回,否则该数据就丢失了。return username"""使用pydantic提供model_validator对多个数据进行复杂验证"""@model_validator(mode="after")def check_password(self):if self.password != self.password2:raise ValueError("密码与确认密码不一致!")# 必须有数据返回,否则该数据就丢失了。return selfif __name__ == '__main__':data = {"username": "admin2", "mobile": "13312345678", "password": "123456", "password2": "123456"}try:user = User(**data)except ValidationError as e:print(e.json())
4. pydantic结合FastAPI对客户端数据进行接收和验证

假设客户端提供的数据结构,如下:

在这里插入图片描述

main.py,代码:

import uvicorn
from datetime import date
from fastapi import FastAPI, Body
from pydantic import BaseModel, Field, field_validatorapp = FastAPI()# 表示已经添加的图书[模拟将来的数据库]
book_list = []class Book(BaseModel):title: str = Field(title="书名")author: str = Field(title="作者")price: float = Field(title="价格")category: str = Field(title="类别")pub_date: date = Field(title="发行时间")count: int = Field(title="数量")@field_validator("title")def check_title(cls, data):"""验证图书标题"""assert data not in book_list, "当前图书已重复添加"# 务必返回验证后的数据,否则后续操作中无法提取title的值了return data@app.post("/book")
async def index(book: Book, username:str= Body(title="创建者")):return {"book": book,"username": username}if __name__ == "__main__":uvicorn.run("main:app", reload=True)
4.1.3.3 接收表单数据

接收的不是 JSON,而是表单字段时,FastAPI提供了Form组件来接收表单数据,同时还提供了File组件来接收上传文件。

不管是表单组件还是文件组件,都需要先使用pip install python-multipart命令进行安装。

pip install python-multipart -i https://pypi.tuna.tsinghua.edu.cn/simple

HTML提供的form表单,仅仅支持了GET和POST请求,是没有其他的请求的,与HTTP协议的请求方法类似,但是不一样。

method描述
get以HTTP协议的GET请求,并通过查询参数把表单数据发送给服务端,不支持上传文件。
post以HTTP协议的POST请求,并通过请求体把表单书发送给服务端,支持上传文件,但是必须声明表单数据的编码格式enctype属性值为multipart/form-data
4.1.3.3.1 接收纯文本表单

接收GET请求的表单,GET类型的表单是不能接收上传文件的。

main.py,代码:

import uvicorn
from fastapi import FastAPI, Formapp = FastAPI()@app.get("/user")
async def index(name: str = Form(title="用户名"), pwd: str = Form(title="密码")):return {"name": name,"pwd": pwd}if __name__ == "__main__":uvicorn.run("main:app", reload=True)

接受POST纯文本表单,支持上传文件。但是我们先使用纯文本表单接收数据。

main.py,代码:

import uvicorn
from fastapi import FastAPI, Form
from typing import Listapp = FastAPI()@app.post("/user")
async def index(username: str=Form(title="用户名"), password: str=Form(title="密码"), city: list[str]=Form(title="城市")):"""上面参数的类型声明中的list,如果python<3.9版本,则需要使用List来代替,List是通过 from typing import List 导入的:param username: 单行文本框:param password: 密码框:param city: 接收类似select下拉框, checkbox多选框的表单项的数据:return:"""return {"username": username,"password": password,"city": city,}if __name__ == "__main__":uvicorn.run("main:app", reload=True)
4.1.3.3.2 接收上传文件

FastAPI中提供的File组件,不仅提供了File对象对上传的中小类型文件进行快速处理,还提供了UploadFile对象对上传的所有类型文件进行详尽处理流程。

使用File进行简单上传文件处理

main.py,代码:

import randomimport uvicorn
from fastapi import FastAPI, Form, File
from datetime import datetime
app = FastAPI()"""接收单个上传的中小文件,并简单处理"""
@app.post("/user")
async def index(avatar: bytes = File(), username: str=Form(title="用户名")):"""先接收上传文件,再接收其他表单数据:param avatar::param username::return:"""# 获取上传文件大小print(f"file_size: {len(avatar)}")# 随机生成文件名,并在将来保存到数据库中filename = datetime.now().strftime("%Y%m%d%H%M%S") + f"{random.randint(1, 9999999):07d}.jpg"with open(f"uploads/{filename}", "wb") as f:f.write(avatar)return {"username": username,"avatar": filename}"""接收多个上传的中小文件,并简单处理"""
@app.post("/books")
async def index(banner: list[bytes] = File(), title: str=Form(title="图书标题")):"""先接收上传文件,再接收其他表单数据:param avatar::param username::return:"""# 获取上传文件的个数:print(f"file_count: {len(banner)}字节")# 随机生成文件名,并在将来保存到数据库中filename = datetime.now().strftime("%Y%m%d%H%M%S") + f"{random.randint(1, 9999999):07d}"# 简单处理多个上传文件for index, file in enumerate(banner):with open(f"uploads/{filename}_{index}.jpg", "wb") as f:f.write(file)return {"title": title,"banner": []}if __name__ == "__main__":uvicorn.run("main:app", reload=True)

上传一个文件,postman操作效果如下:

在这里插入图片描述

上传多个文件,postman操作效果如下:

在这里插入图片描述

使用UploadFile进行上传文件详细处理

main.py,代码:

import random
import uvicorn
from fastapi import FastAPI, Form, File, UploadFile
from datetime import datetime
app = FastAPI()"""接收单个上传的任意大小的文件,并详细处理"""
@app.post("/uploads")
async def uploads(attachment: UploadFile = File(title="课件"), title: str = Form(title="课程名称")):print("文件名: ", attachment.filename)print("文件MIME类型:", attachment.content_type)print("文件大小:", attachment.size)print("文件句柄:", attachment.file)# 保存上传文件with open(f"uploads/{attachment.filename}", "wb") as f:f.write(attachment.file.read())return {"title": title,"attachment": f"uploads/{attachment.filename}"}"""接收多个上传的任意大小的文件,并详细处理"""
@app.post("/multipart")
async def multipart(videos: list[UploadFile] = File(title="课堂录屏"), title: str = Form(title="课时名称")):"""接收多个上传的文件,需要循环:param videos: 视频,这里仅仅举例而已,实际中上传的可以使任意格式的文件,包括图片,音频,文档,压缩包,模型等等:param title::return:"""print("文件数量:", len(videos))# 在循环中循环获取上传的信息filename = datetime.now().strftime("%Y%m%d%H%M%S") + f"{random.randint(1, 9999999):07d}"file_list = []for index, video in enumerate(videos):print(video.content_type)name = f"uploads/{filename}_{index}.{video.filename.split('.')[-1]}"with open(name, "wb") as f:f.write(video.file.read())file_list.append(name)return {"title": title,"attachment": file_list}if __name__ == "__main__":uvicorn.run("main:app", reload=True)

使用postman上传单个文件效果如下:

在这里插入图片描述

使用postman上传多个文件效果如下:

在这里插入图片描述

注意:

如果在上传文件内容要求安全性较高的开发场景,需要根据上传文件content_type来确定文件的格式内容,而不是使用上面代码中直接截取上传文件名后缀的方式。

4.1.4 Reqeust对象操作

有些情况下我们希望能直接访问Request对象。例如我们在路径操作函数中想获取客户端的IP地址,需要在函数中声明Request类型的参数,FastAPI 就会自动传递 Request 对象给这个参数,我们就可以获取到 Request 对象及其属性信息,例如 header、url、cookie、session 等。

import uvicorn
from fastapi import FastAPI, Request
app = FastAPI()@app.get("/req1")
async def req1(request: Request):"""直接获取HTTP请求对象:param request: fastAPI内部的web应用程序会提供Request保存关于HTTP请求报文的所有数据:return:"""# 以下几个属性,在任何的HTTP请求都可以使用。print(request.app is app) # 获取当前应用对象print(request.headers)  # 获取本次请求的所有请求头数据print(request.headers['host'])  # 获取本次请求的所有请求头数据print(request.headers['user-agent'])  # 获取本次请求的所有请求头数据print(request.method) # 本次HTTP请求方法print(request.query_params) # user=xioaming   本次HTTP请求的查询参数print(request.url) #  本次HTTP请求的路径 http://127.0.0.1:8000/req1?user=xioamingreturn {}@app.post("/req2")
async def req2(request: Request):"""直接获取HTTP请求对象:param request: fastAPI内部的web应用程序会提供Request保存关于HTTP请求报文的所有数据:return:"""# 获取请求体[原始数据,bytes类型]body = await request.body()print(body)# 获取请求体[JSON数据,字典类型吗,如果不符合json的话,会报错]data = await request.json()print(data)return {}if __name__ == "__main__":uvicorn.run("main:app", reload=True)
4.1.4.1 FastAPI框架的生命周期

所谓FastAPI的生命周期,指代的是从客户端发送一个HTTP请求,到FastAPI接受请求并返回响应结果这个过程中的整个请求与响应过程,也叫请求的存活周期。

在这里插入图片描述

数据返回给客户端的流程:

在这里插入图片描述

4.2 响应操作

在FastAPI中,所有的数据最终都是通过 Response返回给web应用程序,经过web应用程序进行报文组装后返回给了web服务器。

4.2.1 数据响应
4.2.1.1 响应JSON数据

FastAPI默认了接口函数/接口类方法在返回结果时,默认使用json格式返回,开发者也可以通过fastAPI.responses.JSONResponse来返回json数据的同时,返回自定义状态码与自定义响应头。

main.py,代码:

import jsonimport uvicorn
from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse
app = FastAPI()@app.get("/rep1")
async def get():"""响应json数据:return:"""data = {"name": "xiaoming","age": 17}# # 无法指定返回状态码# return data# 1. return data的本质,如下:# 可以指定返回状态码,也可以返回自定义响应头return JSONResponse(data, headers={"token": "xxxxxx"}, status_code=201)# # 2. JSONResponse的本质,代码如下:# return Response(json.dumps(data), headers={"content-type": "application/json"}, status_code=201)if __name__ == "__main__":uvicorn.run("main:app", reload=True)

上面代码中JSONREsponse调用了父类Response的关系如下:

在这里插入图片描述

4.2.1.2 响应HTML文档

FastAPI提供了fastAPI.responses.HTMLResponse来允许服务端返回html文档数据的同时,返回自定义状态码与自定义响应头。

main.py,代码:

import uvicorn
from fastapi import FastAPI, Response, Form
from fastapi.responses import HTMLResponseapp = FastAPI()@app.get("/login")
async def get():"""响应HTML网页:return:"""html_content = """<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form method="post" action="/dologin">用户名:<input type="text" name="username" ><br><br>密码:<input type="password" name="pwd"><br><br><button>登录</button></form>
</body>
</html>"""# html_content = open("main.html", "r").read()return HTMLResponse(html_content)# # HTMLResponse的本质代码:# return Response(html_content, headers={"content-type": "text/html"})@app.post("/dologin")
async def login(username: str=Form(title="用户名"), pwd: str=Form(title="登录密码")):# 完成把数据保存到数据库中的操作return {"msg": "操作成功!","username": username,}if __name__ == "__main__":uvicorn.run("main:app", reload=True)

上面仅仅是返回一个HTML,实际工作中,不会把所有的HTML文档全部作为pytnon的字符串来保存,而是写成单独的html文件进行处理。但是上面的代码很好的完成了一个由前端发送请求到服务端接收请求的过程。打开浏览器,访问http://127.0.0.1:8000/login,操作如下:

在这里插入图片描述

响应效果:

在这里插入图片描述

4.2.1.3 响应下载文件

FastAPI提供了FileResponse给开发者用于在接口方法/接口类方法中提供下载文件给客户端的。FileResponse也是Response类的子类。FileResponse与JSONRespon、HTMLResponse一样,都是提供了status_code和headers等属性给开发者用于自定义响应头和自定义响应状态码。 main.py,代码:

import uvicorn
from fastapi import FastAPI
from fastapi.responses import FileResponse
app = FastAPI()@app.get("/dw")
async def download(file: str):"""提供下载文件:return:"""# 根据file提供的文件名,让用户下载文件filepath = f"uploads/{file}"  # 此处的文件路径需要根据自己的实际情况编写。return FileResponse(filepath, filename=file)# # FileResponse的底层代码# from fastapi import Response# from mimetypes import guess_type# return Response(open(filepath, "r").read(), headers={#     "content-disposition": f"attachment; filename='{file}'",#     "content-type": guess_type(f"uploads/{file}")# })
if __name__ == "__main__":uvicorn.run("main:app", reload=True)
4.2.1 抛出异常

在FastAPI中提供了HTTPException异常类给开发者用于在接口函数/接口类方法中抛出异常给客户端的。我们实际使用时,可以直接使用HTTPException类或者使用它的子类进行异常的抛出,用于提示客户端对应的错误信息。

main.py,代码:

import os
import uvicorn
from fastapi import FastAPI, HTTPException, status
from fastapi.responses import FileResponseapp = FastAPI()@app.get("/dw")
def download(file: str):"""提供下载文件:return:"""filepath = f"uploads/{file}"  # 此处的文件路径需要根据自己的实际情况编写。# 当客户端提交的数据没有通过验证,我们需要通过抛出异常,提醒客户端if not os.path.isfile(filepath):raise HTTPException(detail="要下载的文件不存在!",status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,headers={"X-Error": "There goes my error"}, # 也可以自定义响应头)return FileResponse(filepath, filename=file)if __name__ == "__main__":uvicorn.run("main:app", reload=True)
4.2.3 响应模型

FastAPI提供了响应模型的作用主要是声明用于返回给客户端的数据格式(字段列表),常用于对返回数据进行脱敏(所谓的脱敏,就是在需要返回的数据中如果存在涉及用户隐私和安全问题的数据上进行混淆或者删减等操作)。

4.2.3.1 基本使用

FastAPI 的路由装饰器中提供了 response_model 参数,声明 return 响应体的模型

# 路径操作,Item就是pydantic提供的BaseModel的子类,用于声明返回数据的格式
@app.post("/items/", response_model=Item)
async def create_item() -> Item:...

FastAPI将使用response_model进行以下操作:

  • 将输出数据转换为response_model中声明的数据类型。
  • 验证数据结构和类型
  • 将输出数据限制为该model定义的实例
  • 添加到OpenAPI接口文档中
  • 开发者就可以直接通过接口文档中直接查看到返回的数据结构。

案例:注册功能

要求:输入账号、密码、手机号、邮箱,注册成功后返回个人信息[但是不包含密码,手机号等敏感数据]

main.py,代码:

import uvicorn, re
from fastapi import FastAPI, status, Body
from pydantic import BaseModel, Field, validate_email, model_validatorapp = FastAPI()class UserIn(BaseModel):username: str =  Field(title="用户名")password: str = Field(title="密码")mobile: str = Field(title="手机号")email: str = Field(title="邮箱", validate_default=validate_email)class UserOut(BaseModel):username: str =  Field(title="用户名")email: str = Field(title="邮箱", validate_default=validate_email)mobile: str = Field(title="手机号")@model_validator(mode="after")def models(self):"""脱敏操作"""# \\1 代表第一个小括号中正则捕获到的内容, \\n 表示第n个小括号中捕获到的内容self.mobile = re.sub("(\d{3})\d{4}(\d{4})", "\\1****\\2", self.mobile)return self@app.post("/users", status_code=status.HTTP_201_CREATED, response_model=UserOut)
async def add_user(user: UserIn = Body()):return userif __name__ == '__main__':uvicorn.run("main:app", reload=True)

在FastAPI新版本中,不需要使用response_model已经被简化了。main.py,代码:

import uvicorn, re
from fastapi import FastAPI, status, Body
from pydantic import BaseModel, Field, validate_email, model_validatorapp = FastAPI()class UserIn(BaseModel):username: str =  Field(title="用户名")password: str = Field(title="密码")mobile: str = Field(title="手机号")email: str = Field(title="邮箱", validate_default=validate_email)class UserOut(BaseModel):username: str =  Field(title="用户名")email: str = Field(title="邮箱", validate_default=validate_email)mobile: str = Field(title="手机号")@model_validator(mode="after")def models(self):"""脱敏操作"""# \\1 代表第一个小括号中正则捕获到的内容, \\n 表示第n个小括号中捕获到的内容self.mobile = re.sub("(\d{3})\d{4}(\d{4})", "\\1****\\2", self.mobile)return self@app.post("/users", status_code=status.HTTP_201_CREATED)
async def add_user(user: UserIn = Body()) -> UserOut:return userif __name__ == '__main__':uvicorn.run("main:app", reload=True)

postman中操作效果如下:

在这里插入图片描述

4.2.3.2 黑名单与白名单

在开发中有时候返回给客户端的数据可能存在几十上百个字段的情况,此时让服务端开发者声明一个拥有上百个属性的数据模型,肯定是一个比较折磨人的事情,所以FastAPI提供了响应模型的黑名单和白名单两个属性。

黑名单(response_model_exclude):就是在名单中出现的字段,不要返回给客户端。

白名单(response_model_include):就是只有名单中出现的字段,才返回给客户端。

黑名单与白名单是互斥的!!!

import uvicorn, re
from fastapi import FastAPI, status, Body
from pydantic import BaseModel, Field, validate_email, model_validatorapp = FastAPI()class UserIn(BaseModel):username: str =  Field(title="用户名")password: str = Field(title="密码")mobile: str = Field(title="手机号")email: str = Field(title="邮箱", validate_default=validate_email)"""黑名单"""
@app.post("/users1", status_code=status.HTTP_201_CREATED, response_model_exclude=["mobile", "password"])
async def add_user1(user: UserIn = Body()) -> UserIn:return user"""白名单"""
@app.post("/users2", status_code=status.HTTP_201_CREATED, response_model_include=["username", "email"])
async def add_user2(user: UserIn = Body()) -> UserIn:return userif __name__ == '__main__':uvicorn.run("main:app", reload=True)

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

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

相关文章

吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)2.5-2.6

目录 第四门课 卷积神经网络&#xff08;Convolutional Neural Networks&#xff09;第二周 深度卷积网络&#xff1a;实例探究&#xff08;Deep convolutional models: case studies&#xff09;2.5 网络中的网络以及 11 卷积&#xff08;Network in Network and 11 convoluti…

【AI知识点】批归一化(Batch Normalization)

批归一化&#xff08;Batch Normalization&#xff0c;BN&#xff09; 是一种用于加速神经网络训练并提高模型稳定性的方法&#xff0c;最早由 Sergey Ioffe 和 Christian Szegedy 在 2015 年提出。批归一化通过在每一层对神经网络中的激活值进行标准化&#xff0c;使得每一层的…

D29【python 接口自动化学习】- python基础之输入输出与文件操作

day29 格式化输出 学习日期&#xff1a;20241006 学习目标&#xff1a;输入输出与文件操作&#xfe63;-41 格式化输出&#xff1a;如何将执行结果通过屏幕输出&#xff1f; 学习笔记&#xff1a; 三种常用的格式化输出方式 百分号方式 format函数方式 总结 1. 格式化输出…

在ubuntu好部署jenkins发布vue项目时遇到的一些问题及解决方法以及使用jenkins发布vue项目-npm自动打包发布的实现

一、在ubuntu好部署jenkins发布vue项目时遇到的一些问题及解决方法 1. 问题&#xff1a;webpack-dev-server不是内部或外部命令&#xff0c;也不是可运行的程序 解决&#xff1a;使用webpack要安装webpack-cli这个包&#xff0c;才可以调用webpack和webpack-dev-server这些命…

Hive3.x版本调优总结

文章目录 第 1 章 Explain 查看执行计划&#xff08;重点&#xff09;1.1 创建测试用表1&#xff09;建大表、小表和 JOIN 后表的语句2&#xff09;分别向大表和小表中导入数据 1.2 基本语法1.3 案例实操 第 2 章 Hive 建表优化2.1 分区表2.1.1 分区表基本操作2.1.2 二级分区2.…

虚拟机 VMware 安装 macOS

macOS 界面 MAC OS IOS下载&#xff1a; amacOS Monterey by Techrechard.comwmacOS Monterey by Techrechard.com 下载&#xff1a;Unlocker-v2.0.1-x64 Mac OS X 虚拟机中更改屏幕分辨率 终端输入命令&#xff1a; sudo defaults write /Library/Preferences/com.apple.w…

2-114 基于matlab的CA模型

基于matlab的CA模型&#xff0c;Singer模型对单机动目标进行跟踪算法&#xff0c;具有10页实验文档。采用蒙特卡罗方法对一个二坐标雷达对一平面上运动的目标进行观测&#xff0c;得到跟踪滤波结果。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&#xff1a;2-114 …

Linux:进程的创建、终止和等待

一、进程创建 1.1 fork函数初识 #include pid_t fork(void); 返回值&#xff1a;子进程中返回0&#xff0c;父进程返回子进程id&#xff0c;出错返回-1 调用fork函数后&#xff0c;内核做了下面的工作&#xff1a; 1、创建了一个子进程的PCB结构体、并拷贝一份相同的进程地址…

Stable Diffusion绘画 | IP角色多视图生成技巧

在游戏设计、小说推文、角色设计里面&#xff0c;很多场景都运用到IP角色的多视图。 人物角色多视图 第1步&#xff0c;输入提示词&#xff1a; 第2步&#xff0c;由于要在同一张图片中生成多角度的并排展示&#xff0c;需要修改图片的分辨率&#xff08;尤其是宽度&#xff…

Pytorch实现心跳信号分类识别(支持LSTM,GRU,TCN模型)

Pytorch实现心跳信号分类识别(支持LSTM,GRU,TCN模型&#xff09; 目录 Pytorch实现心跳信号分类识别(支持LSTM,GRU,TCN模型&#xff09; 1. 项目说明 2. 数据说明 &#xff08;1&#xff09;心跳信号分类预测数据集 3. 模型训练 &#xff08;1&#xff09;项目安装 &am…

MoveIt2-humble----在 RViz 中实现可视化

官方文档上的教程&#xff0c;从moveit1的melodic到moveit2的foxy基本一致&#xff0c;但是从最新的humble开始有了很大的变化&#xff0c;其中之一便是 lambda表达式 的广泛使用。 本节为教程的第二节&#xff0c;会介绍一个工具&#xff08;moveit_visual_tools&#xff09;…

运动员场景分割系统源码&数据集分享

运动员场景分割系统源码&#xff06;数据集分享 [yolov8-seg-HGNetV2&#xff06;yolov8-seg-aux等50全套改进创新点发刊_一键训练教程_Web前端展示] 1.研究背景与意义 项目参考ILSVRC ImageNet Large Scale Visual Recognition Challenge 项目来源AAAI Global Al lnnovati…

麒麟 操作系统介绍| 银河麒麟和中标麒麟操作系统| Kylin 麒麟iso 镜像下载地址 银河麒麟操作系统v10 |

目录 #申请试用小技巧&#xff0c; 所有麒麟系列的版本如下 详细介绍如下&#xff1a; 银河麒麟高级服务器操作系统 V10 1. 龙芯-MIPS64el 版 2. 申威版 3. 兆芯版 4. 海光版 5. 飞腾版 6. 鲲鹏版 7. AMD64版 8. 龙芯-LoongArch64 版 9. ARM64版 银河麒麟桌面操作…

SpringMVC源码-AbstractUrlHandlerMapping处理器映射器将实现Controller接口的方式定义的路径存储进去

DispatcherServlet的initStrategies方法用来初始化SpringMVC的九大内置组件 initStrategies protected void initStrategies(ApplicationContext context) {// 初始化 MultipartResolver:主要用来处理文件上传.如果定义过当前类型的bean对象&#xff0c;那么直接获取&#xff0…

【学习笔记】kruskal重构树

前言 最近一场div2没开出C2&#xff0c;猛掉104分。 赛后补E&#xff0c;发现自己连E1都没思路&#xff0c;一问才知道是kruskal重构树。 好吧&#xff0c;OI时期欠下的债该还了。 kruskal重构树是什么 它是一棵 2 n − 1 2n-1 2n−1 个点的二叉树。点有点权&#xff0c;下…

异常场景分析

优质博文&#xff1a;IT-BLOG-CN 为了防止黑客从前台异常信息&#xff0c;对系统进行攻击。同时&#xff0c;为了提高用户体验&#xff0c;我们都会都抛出的异常进行拦截处理。 一、异常处理类 Java把异常当做是破坏正常流程的一个事件&#xff0c;当事件发生后&#xff0c;…

https访问报错:net::ERR_CERT_DATE_INVALLD

目录 简介异常排查原因解决补充 简介 访问https资源出现报错 异常 排查 将地址拿到浏览器进行访问&#xff0c;可以很清晰的看到出现该问题的原因 原因 1、SSL证书已过期 2、服务器日期不准&#xff0c;不在证书有效期 解决 1、重新申请SSL证书&#xff0c;并配置 2、校正…

VMware桥接模式无法连接网络

windows下打开控制面板&#xff0c;找到WLAN&#xff0c;记住下面的名称&#xff08;带有VMware的都是虚拟机的网卡&#xff0c;要找到物理主机的网卡&#xff09; 回到VMware&#xff0c;编辑——打开虚拟网络编辑器 桥接选择上面的WLAN下的网络名称&#xff0c;确定即可。&…

【学习笔记】手写一个简单的 Spring MVC

目录 一、什么是Spring MVC &#xff1f; Spring 和 Spring MVC 的区别&#xff1f; Spring MVC 的运行流程&#xff1f; 二、实现步骤 1. DispatcherServlet 1. 创建一个中央分发器 拦截所有请求 测试 2. 接管 IOC 容器 1. 创建配置文件 2. 修改 web.xml 配置文件 …

输电线路悬垂线夹检测无人机航拍图像数据集,总共1600左右图片,悬垂线夹识别,标注为voc格式

输电线路悬垂线夹检测无人机航拍图像数据集&#xff0c;总共1600左右图片&#xff0c;悬垂线夹识别&#xff0c;标注为voc格式 输电线路悬垂线夹检测无人机航拍图像数据集介绍 数据集名称 输电线路悬垂线夹检测数据集 (Transmission Line Fittings Detection Dataset) 数据集…