当前位置:   article > 正文

fastapi响应数据处理_fastapi中間件修改響應

fastapi中間件修改響應

密码使用场景

请求体和响应体的数据格式通常是不同的,如前端用户给后端服务器传递用户名、邮箱、手机号、密码等信息,后端给前端通常不会返回密码
EmailStr需要额外安装:pip install pydantic[email]
通过路径操作,path operation定义响应体的格式
请求体和响应体有关联的,可以通过定义共同的基类来节省代码

from typing import Optional, List
from pydantic import BaseModel, EmailStr

app04 = APIRouter()

"""Response Model 响应模型"""


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    mobile: str = "10086"
    address: str = None
    full_name: Optional[str] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr  # 用 EmailStr 需要 pip install pydantic[email]
    mobile: str = "10086"
    address: str = None
    full_name: Optional[str] = None


users = {
    "user01": {"username": "user01", "password": "123123", "email": "user01@example.com"},
    "user02": {"username": "user02", "password": "123456", "email": "user02@example.com", "mobile": "110"}
}


@app04.post("/response_model/", response_model=UserOut, response_model_exclude_unset=True)
async def response_model(user: UserIn):
    """response_model_exclude_unset=True表示默认值不包含在响应中,仅包含实际给的值,如果实际给的值与默认值相同也会包含在响应中"""
    print(user.password)  # password不会被返回
    # return user
    return users["user01"]


@app04.post(
    "/response_model/attributes",
    response_model=UserOut,
    # response_model=Union[UserIn, UserOut],    # 返回两者的并集字段
    # response_model=List[UserOut],      # 返回结果是多个包括userout类型的列表
    response_model_include=["username", "email", "mobile"],     # 需要在结果中包含的字段
    response_model_exclude=["mobile"]     # 需要排除的字段
)
async def response_model_attributes(user: UserIn):
    # del user.password  # Union[UserIn, UserOut]后,删除password属性也能返回成功
    return user
    # return [user, user]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

表单数据处理

from fastapi import Form

@app04.post("/login/")
async def login(username: str = Form(...), password: str = Form(...)):  # 定义表单类型,...为必填
    """用Form类需要pip install python-multipart; Form类的元数据和校验方法类似Body/Query/Path/Cookie"""
    return {"username": username}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

单文件,多文件上传

需要导入file和uploadfile,当使用file文件会用2进制形式写入内存,只适合小文件上传,文件太大会爆内存

@app04.post("/file")
# 如果要上传多个文件 files: List[bytes] = File(...)
async def file_(file: bytes = File(...)):
    return {"file_size": len(file)}
  • 1
  • 2
  • 3
  • 4

在docs中可以看到定义了file类型后,请求就变为了form-data,在vue端编写请求的时候,可以参考
在这里插入图片描述
上传大文件需要使用uploadfile,使用UploadFile类的优势:

  1. 文件存储在内存中,使用的内存达到阈值后,将被保存在磁盘中
  2. 适合于图片、视频大文件
  3. 可以获取上传的文件的元数据,如文件名,创建时间等
  4. 有文件对象的异步接口,可以异步方式读取或更改文件
  5. 上传的文件是Python文件对象,可以使用write(), read(), seek(), close()操作
async def upload_files(files: List[UploadFile] = File(...)):
    for file in files:
        contents = await file.read()
        print(contents)
    return {"filename": files[0].filename, "content_type": files[0].content_type} # 返回第一个文件的数据
  • 1
  • 2
  • 3
  • 4
  • 5

可以看到return输出的文件类型为application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
在用python或其它语言时,实现下载excel功能或者是上传,要使用content_type定义类型

@app.get("/File")
async def get_file():
	filepath = "./data/demo.xlsx"
	filename = "demo.xlsx"
	headers = {
		"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
	}
	return FileResponse(filepath, filename=filename, headers=headers)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在终端看到的输出就是乱码
https://www.w3school.com.cn/media/media_mimeref.asp 可以看到其它常用格式的content_type

静态文件配置

静态文件也属于一种返回的形式,需要配置,在项目根路径新建static文件夹,之后在run.py即运行主文件中挂载,对于fastapi而言,static只是一个独立应用,与fastapi无关
app.mount(self,path,app,name) ,特别注意,只能挂在到FastAPI中不要挂到APIRouter中

from fastapi.staticfiles import StaticFiles
app.mount(path='/static', app=StaticFiles(directory='./static'), name='static')
  • 1
  • 2

路径操作配置

主要用于响应的描述,响应的数据格式,响应状态码等。
deprecated=True ,用于标注该接口已经废弃掉,但依然可以使用
tags=[‘’,‘’] ,接口的描述,可以添加多个,但是不建议,因为会很混乱

响应状态码

状态码可以在路径中的status_code中定义

from fastapi import status
@app04.post("/status_attribute", status_code=status.HTTP_200_OK)
async def status_attribute():
    print(type(status.HTTP_200_OK))    # int类型 <class 'int'>
    return {"返回的内容": "返回200状态码"}
  • 1
  • 2
  • 3
  • 4
  • 5

如上,推荐使用status,不建议直接返回数字,因为语义化更明确。执行之后在docs中可以看到相应的code在这里插入图片描述

fastapi应用的配置

在主文件中的FastAPI可以配置应用,title标题,description简介,version版本号,docs_url接口测试地址(默认是/docs),redoc_url(不能操作,可以给用户参考用,默认/redocs)

错误处理(不常用)

通过 from fastapi import HTTPException 捕获错误
if判断,满足条件后,raise抛出raise HTTPException(status_code=404, detail="City not found!", headers={"X-Error": "Error"}),headers为在response headers中插入值
在这里插入图片描述
想所有应用都用自定义的错误相应,就要在主文件run.py中配置

from fastapi.exceptions import RequestValidationError  # 请求错误校验处理
from fastapi.responses import PlainTextResponse   # 文本形式返回response
from fastapi import HTTPException
from starlette.exceptions import HTTPException as StarletteHTTPException  # fastapi建立在starlette基础之上,所以与上一项的导入相同
  • 1
  • 2
  • 3
  • 4

重写http异常处理,其中request必须有,exc是错误

@app.exception_handler(StarletteHTTPException)  # 重写HTTPException异常处理器,把原来的错误信息从json改为文本形式
async def http_exception_handler(request, exc):
    return PlainTextResponse(str(exc.detail), status_code=exc.status_code)
  • 1
  • 2
  • 3

PlainTextResponse的作用是:返回一些纯文本数据
重写请求验证的错误处理

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
    return PlainTextResponse(str(exc), status_code=400)
  • 1
  • 2
  • 3

新建路由,验证错误处理

@app04.get("/http_exception/{city_id}")
async def override_http_exception(city_id: int):
    if city_id == 1:
        raise HTTPException(status_code=418, detail="Nope! I don't like 1.")
    return {"city_id": city_id}
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/416447
推荐阅读
相关标签
  

闽ICP备14008679号