概述

fastapi如果pydantic对输入数据验证出现不符合的情况,默认情况下会以422的格式返回。
但是说实话这个格式实在是太丑。
最主要的原因是很可能不符合大家前后端交互的错误类型。
当然返回内容不是中文也很重要。(这种事交给前端的话前端大概会打死我)

解决方案

在初始化app的时候,可以增加自定义的报错。
目前fastapi很贴心的支持三种报错捕捉和替换默认处理。

Exception

这种错误就是一般情况下的python报错,这种可以通过捕捉的方式自定义返回值

HTTPException

包括400,401等一般情况下的http错误的处理

RequestValidationError

这就是经典的422报错了,请求参数错误。

解决方案

解决方案放如下(请先跳到重点部分查看)

# -*- encoding: utf-8 -*-
"""
@File    : app.py
@Time    : 2020/12/2 22:57
@Author  : chise
@Email   : chise123@live.com
@Software: PyCharm
@info    :
"""
import json
import logging
import typing

from fastapi import Depends, FastAPI, HTTPException
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import ORJSONResponse
from starlette.requests import Request
from starlette.responses import PlainTextResponse, JSONResponse
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_403_FORBIDDEN, HTTP_422_UNPROCESSABLE_ENTITY

from example import settings

from example.errors import Forbidden, TokenInvalid, UnKnownError, UserBaned
from example.exceptions import ErrorException, UserBanedError
# from .routes import api_router, notify_router, yl_notify_router
from .views import router

logger = logging.getLogger("example.app1")


async def error_exception_handler(request: Request, exc: ErrorException):
    if isinstance(exc, UserBanedError):
        ret = UserBaned().dict()
        if settings.DEBUG:
            return ORJSONResponse(ret)
        return AesResponse(ret)


async def http_exception_handler(request: Request, exc: HTTPException) -> JSONResponse:
    detial = exc.detail
    if exc.status_code == HTTP_401_UNAUTHORIZED:
        ret = TokenInvalid(msg=exc.detail).dict()
    elif exc.status_code == HTTP_403_FORBIDDEN:
        ret = Forbidden(msg=exc.detail).dict()
    else:
        logger.error(f"HTTPException: {exc.detail}", exc_info=True)
        ret = UnKnownError(msg=exc.detail).dict()
    if settings.DEBUG:
        return JSONResponse(ret)
    return AesResponse(ret)


async def request_validation_exception_handler(
        request: Request, exc: RequestValidationError
) -> JSONResponse:
    """
    捕捉422报错并进行自定义处理
    :param request:
    :param exc:
    :return:
    """
    x = exc.errors()
    return JSONResponse(
        status_code=HTTP_422_UNPROCESSABLE_ENTITY,
        content={"detail": jsonable_encoder(exc.errors())},
    )


class AesResponse(PlainTextResponse):
    def render(self, content: typing.Any) -> bytes:
        """
        返回类,可以在这里进行返回数据全局加密等
        :param content:
        :return:
        """
        content = json.dumps(content)
        self.media_type = "application/json"
        return super(AesResponse, self).render(content)


app = FastAPI(
    title="app1的接口文档",
    debug=settings.DEBUG,
    default_response_class=AesResponse,  # 自定义返回类
)
#重点!!!,通过加入自定义的函数,可以替换默认的报错函数
app.add_exception_handler(ErrorException, error_exception_handler)
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(RequestValidationError, request_validation_exception_handler)
app.include_router(router=router, prefix="/app1")


Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐