Python框架篇(4):FastApi-错误处理

@提示: 微信搜索【猿码记】回复 【fastapi】即可获取源码信息~

1.验证错误

1.1 默认返回

当传参不符合模型验证规则时,默认错误信息和格式返回如下:

{
  "detail": [
    {
      "loc": [
        "body",
        "age"
      ],
      "msg""ensure this value is greater than 18",
      "type""value_error.number.not_gt",
      "ctx": {
        "limit_value"18
      }
    },
    {
      "loc": [
        "body",
        "likes"
      ],
      "msg""ensure this value has at least 2 items",
      "type""value_error.list.min_items",
      "ctx": {
        "limit_value"2
      }
    }
  ]
}

在上篇文章 Python框架篇(3):FastApi-响应模型中,我们强调的是接口对外输出结构应该一致,所以即便参数错误应该输出以下结构:

{
    "code":-1,
    "msg":"具体错误信息...",
    "data"null,
    "additional":{
        "time":"2023-12-04 19:00:23",
        "trace_id":"cc1b12a5dfee26a7dcc29fe47dcfbde0"
    }
}

按照官方文档说法,我们需要自定义错误处理器,并以此来覆盖框架默认的异常处理器,参数验证错误处理器默认走的是RequestValidationError,所以覆盖它就行,下面是实现步骤

1.2 自定义处理器

新建包app/errors,并新增文件validation_error.py,文件内容如下:

from fastapi import Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from app.types import response
from fastapi.encoders import jsonable_encoder


async def validationExceptionHandler(request: Request, exc: RequestValidationError):
    """ 自定义参数验证异常错误"""
    errMsg = ""
    for error in exc.errors():
        errMsg += ".".join(error.get("loc")) + ":" + error.get("msg") + ";"
    # 这里response.ResponseFail是上篇文章中的内容
    return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(response.ResponseFail(errMsg)))

在包app/errors/__init__.py引用,并封装统一注册方法:

from fastapi import FastAPI
from .validation_error import validationExceptionHandler
from fastapi.exceptions import RequestValidationError


def registerCustomErrorHandle(server: FastAPI):
    """ 统一注册自定义错误处理器"""
    # 注册参数验证错误,并覆盖模式RequestValidationError
    server.add_exception_handler(RequestValidationError, validationExceptionHandler)

1.3 注册&覆盖

main.py中调用registerCustomErrorHandle

# 引入
from app import errors

server = FastAPI(redoc_url=None, docs_url="/apidoc", title="FastAPI学习")
# 注册自定义错误处理器
errors.registerCustomErrorHandle(server)
...

@注:这里把之前的变量app改成server

1.4 验证

alt

2.路由错误

路由错误常见的一般分为以下两种:

  • 404:访问不存在的接口地址;
  • 405: 接口定义的请求方式是 POST,当时使用 GET 方式请求时;

2.1 默认返回

// 当访问不存在路由时
{
    "detail""Not Found"
}
// 当访问方式不对时
{
    "detail""Method Not Allowed"
}

2.2 自定义处理器

新建包app/errors,并新增文件http_error.py,文件内容如下:

from fastapi import status
from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse
from starlette.exceptions import HTTPException
from app.types import response

async def httpExceptionHandler(request, exc: HTTPException) -> JSONResponse:
    """自定义处理HTTPException"""
    print("request:", request)
    print("status_code:", exc.status_code)
    if exc.status_code == status.HTTP_404_NOT_FOUND:
        # 处理404错误
        return JSONResponse(
            content=jsonable_encoder(response.ResponseFail("接口路由不存在~")),
            status_code=status.HTTP_200_OK,
        )
    elif exc.status_code == status.HTTP_405_METHOD_NOT_ALLOWED:
        # 处理405错误
        return JSONResponse(
            content=jsonable_encoder(response.ResponseFail("请求方式错误,请查看文档确认~")),
            status_code=status.HTTP_200_OK,
        )
    else:
        return JSONResponse(
            content=jsonable_encoder(response.ResponseFail(str(exc))),
            status_code=status.HTTP_200_OK,
        )

2.3 注册&覆盖

修改app/errors/__init__.py文件中的统一注册方法registerCustomErrorHandle

from fastapi import FastAPI
from .validation_error import validationExceptionHandler
from .http_error import httpExceptionHandler
from fastapi.exceptions import RequestValidationError
from starlette.exceptions import HTTPException as StarletteHTTPException

def registerCustomErrorHandle(server: FastAPI):
    """ 统一注册自定义错误处理器 """
    # 注册参数验证错误,并覆盖模式RequestValidationError
    server.add_exception_handler(RequestValidationError, validationExceptionHandler)
    # 错误处理StarletteHTTPException
    server.add_exception_handler(StarletteHTTPException, httpExceptionHandler)

@注意:这里覆盖的错误是:starlette.exceptions包中的HTTPException,不是这个包fastapi.exceptions,否则不会生效!

2.4 验证

// 当访问不存在路由时
{
    "code"-1,
    "msg""接口路由不存在~",
    "data"null,
    "additional": {
        "time""2023-12-08 19:45:28",
        "trace_id""0c9990bb9292dc39909c6ebefc0a8684"
    }
}


// 当访问方式不对时
{
    "code"-1,
    "msg""请求方式错误,请查看文档确认~",
    "data"null,
    "additional": {
        "time""2023-12-08 19:45:55",
        "trace_id""816d92949542040bfdb63922fcdb6ae9"
    }
}

3.翻译参数错误

在上面验证错误使用中,我们可以看到返回的错误信息是英文的,那么怎么翻译成中文呢,在官方文档中未找到使用方法,后来在网上搜到需要使用error_msg_templates这个属性,按照网上示例发现未为生效,后来在pydantic官网又看到这个属性居然在后来的版本中删除了.... :joy:

alt

官方文档: Changes to config:https://docs.pydantic.dev/latest/migration/#changes-to-config

找不到正规途径,只能使用野蛮方法了....

3.1 分析错误对象

alt

从这个错误对象,我们可以简单看出关键节点:type(错误类型)、loc(字段)、ctx(限制信息)

3.2 定义错误模版

在包app/config,并新增文件validate_template_config.py,文件内容如下:

# 错误模版
validateChineseDict = {
    "value_error.number.not_gt""{},值不能大于:{}",
    "value_error.number.not_ge""{},值不能小于等于:{}",
    "value_error.list.min_items""{},元素个数至少为:{}",
    "value_error.str.regex""{},不满足规则:{}"
}

# 关键词显示的错误
keyErrorChineseDict = {
    "phone""手机号格式不正确~"
}

app/config/__init__.py,引入变量配置,文件内容如下:

from .validate_template_config import validateChineseDict, keyErrorChineseDict

3.3 改造自定义处理器

修改文件app/errors/validation_error.py,修改后内容如下:

from fastapi import Request, status
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from app.types import response
from app import config
from fastapi.encoders import jsonable_encoder


async def validationExceptionHandler(request: Request, exc: RequestValidationError):
    """ 自定义参数验证异常错误"""
    errMsg = ""
    for error in exc.errors():
        fieldName = ".".join(error.get("loc"))
        errType = error.get("type")
        if errType in config.validateChineseDict:
            # 在定义错误模版中,并翻译出内容
            translateMsg = translate(fieldName, errType, error.get("ctx")) + "; "
            if translateMsg:
                errMsg += translateMsg
        else:
            # 不在定义模型,显示原始错误
            errMsg += ".".join(error.get("loc")) + "[" + error.get("type") + "]:" + error.get("msg") + "; "

    # 替换body.
    errMsg = errMsg.replace("body.""")
    # 返回
    return JSONResponse(status_code=status.HTTP_200_OK, content=jsonable_encoder(response.ResponseFail(errMsg)))


def translate(fieldName: str, errType: str, limitDict: dict) -> str:
    """ 翻译错误信息"""
    # 先判断是否满足关键词错误
    for k, v in config.keyErrorChineseDict.items():
        if fieldName.find(k) != -1:
            return v

    limitValList = limitDict.values()
    try:
        return config.validateChineseDict.get(errType).format(fieldName, *limitValList)
    except Exception as e:
        return ""

python3.10/site-packages/pydantic/errors.py文件中,定义了经常使用的错误模版,可以跟结合本地实际情况,查看具体代码:

alt

3.4 验证结果

alt

@注意:上面方法,只是提供一种解决思路,如果有更好的方式,喜欢能留言通知,一起学习~

4.系统错误

在厉害的程序员都无法避免程序错误,特别是运行中遇到的异常。如果遇到异常时,我们不希望用户看到500,或者页面崩溃。

4.1 默认返回

alt

4.2 自定义处理器

新建包app/errors,并新增文件app_error.py,文件内容如下:

from fastapi import status
from fastapi.encoders import jsonable_encoder
from fastapi.requests import Request
from fastapi.responses import JSONResponse
from app.types import response


async def appExceptionHandler(request: Request, exc: Exception):
    """自定义全局系统错误"""
    return JSONResponse(
        content=jsonable_encoder(response.ResponseFail("系统运行异常,稍后重试~")),
        status_code=status.HTTP_200_OK,
    )

4.3 注册&覆盖

修改app/errors/__init__.py文件中的统一注册方法registerCustomErrorHandle

def registerCustomErrorHandle(server: FastAPI):
    """ 统一注册自定义错误处理器 """
    # 注册参数验证错误,并覆盖模式RequestValidationError
    server.add_exception_handler(RequestValidationError, validationExceptionHandler)
    # 错误处理StarletteHTTPException
    server.add_exception_handler(StarletteHTTPException, httpExceptionHandler)
    # 自定义全局系统错误
    server.add_exception_handler(Exception, appExceptionHandler)

4.4 验证

alt

本文由 mdnice 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

22、pytest多个参数化的组合

官方实例 # content of test_multi_parametrie.py import pytestpytest.mark.parametrize("x",[0,1]) pytest.mark.parametrize("y",[2,3]) def test_foo(x,y):print("{}-{}".format(x,y))pass解读与实操 要获得多个参数化参数的所有组合&…

科学指南针助力江西高校开展《透射电子显微镜简介及案例分析课程》讲座

2023年11月,科学指南针与江西各大高校合作,共同开展了一场关于《透射电子显微镜的简介及案例分析课程》讲座。该讲座旨在加强学生对于透射电子显微镜的了解,提高他们在科学研究中的实践能力。 透射电子显微镜(简称TEM&#xff09…

【LeetCode】每日一题 2023_12_9 下一个更大的数值平衡数(枚举/打表二分)

文章目录 刷题前唠嗑题目:下一个更大的数值平衡数题目描述代码与解题思路官方解法 结语 刷题前唠嗑 LeetCode?启动!!! 题目:下一个更大的数值平衡数 题目链接:2048. 下一个更大的数值平衡数 …

C++11原子操作atomic

文章目录 原子操作atomic原子操作的相关函数原子操作的特点“平凡的”与“合格的” 原子操作atomic 前面我们介绍了互斥锁等一系列多线程相关操作,这里我们来说下原子操作atomic。 可以理解为原子变量就是将上面的操作进行了整合的一个全新变量,但是实际…

Qt 容器QGroupBox带有标题的组框框架

控件简介 QGroupBox 小部件提供一个带有标题的组框框架。一般与一组或者是同类型的部件一起使用。教你会用,怎么用的强大就靠你了靓仔、靓妹。 用法示例 例 qgroupbox,组框示例(难度:简单),使用 3 个 QRadioButton 单选框按钮,与QVBoxLayout(垂直布局)来展示组框的…

远程控制如何赋能智能制造?贝锐向日葵制造业场景案例解析

随着数字化转型在制造业的不断深入,企业在产线端也逐渐投入更多智能化设备,数字化、智能化设备其中一个比较显著的优势就是可以依托互联网实现远程运维和调试,大大提升产线设备的稳定性和工作效率;而远程调试运维一个重要的实现方…

数据表排序

指针用的有点少了&#xff0c;有点不适应 用的冒泡排序 代码如下&#xff1a; #include<stdio.h> int num[100][100]; int * p[100], jud[100]; int judge(int i, int j, int rank); int m, n, k;int main(void) {scanf("%d%d%d", &m, &n, &k);f…

飞天使-linux操作的一些技巧与知识点

命令行光标移动到行首行尾 ctrl a 跳到首 ctrl e 跳到尾/etc/passwd rpm 包格式 RPM&#xff08;Red Hat Package Manager&#xff09;是一种常用的Linux软件包管理系统&#xff0c;它使用特定的命名规则来标识和命名软件包。RPM包的名称格式通常遵循以下规则&#xff1a;…

Flutter 开发问题摘要

系统&#xff1a;MacOS 14 开发工具&#xff1a;vscode Flutter版本&#xff1a;3.16.3 1.Error: To set up CocoaPods for ARM macOS, run: 解决方式&#xff1a; 在项目的ios文件目录下面执行下面的命令&#xff1a; arch -x86_64 pod install 执行结果&#xff1a;

SVPWM原理及simulink

关注微♥“电击小子程高兴的MATLAB小屋”获得专属优惠 一.SVPWM原理 SPWM常用于变频调速控制系统&#xff0c;经典的SPWM控制主要目的是使变频器的输出电压尽量接近正弦波&#xff0c;并未关注输出的电流波形。而矢量控制的最终目的是得到圆形的旋转磁场&#xff0c;这样就要求…

pr抖音素材42个手机竖屏抖音视频转场特效PR剪辑模板

酷炫、富有创意的Premiere Pro 视频转场动画过渡效果pr模板免费下载。增强内容演示、幻灯片、抖音、社交媒体广告、预告片、促销等视频画面切换效果。 来自PR模板网&#xff1a;https://prmuban.com/36404.html

TCP对数据的拆分

应用程序的数据一般都比较大&#xff0c;因此TCP会按照网络包的大小对数据进行拆分。 当发送缓冲区中的数据超过MSS的长度&#xff0c;数据会被以MSS长度为单位进行拆分&#xff0c;拆分出来的数据块被放进单独的网路包中。 根据发送缓冲区中的数据拆分情况&#xff0c;当判断…

12.8 作业

1&#xff0c; 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#…

PyQt6 QCalendarWidget日历控件

​锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计39条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话…

Python random模块及用法

random 模块主要包含生成伪随机数的各种功能变量和函数。 在 Python 的交互式解释器中先导入 random 模块&#xff0c;然后输入 random.__all__ 命令&#xff08;__all__ 变量代表了该模块开放的公开接口&#xff09;&#xff0c;即可看到该模块所包含的全部属性和函数&#x…

第二十一章网络通信总结

21.1 网络程序设计基础 Java网络程序设计基础涉及使用Java编程语言创建网络应用程序。这通常涉及到使用Java的网络API&#xff0c;如java.net包&#xff0c;以建立客户端和服务器之间的通信。 基本步骤包括&#xff1a; 1.创建服务器&#xff1a; 使用ServerSocket类创建服务…

Day05 linux高级系统设计 - 管道

复制文件描述符 dup函数 作用&#xff1a; 文件描述符复制 语法&#xff1a; #include <unistd.h> int dup (int oldfd); 参数&#xff1a; 所需复制得文件描述符 返回值&#xff1a; 复制到的文件描述符 功能&#xff1a; 从文件描述符表中&#xff0c;找一个最小…

SSH原理与应用与探索

Secure Shell(SSH 安全外壳协议) 是由 IETF(The Internet Engineering Task Force) 制定的建立在应用层基础上的安全网络协议。它是专为远程登录会话(甚至可以用Windows远程登录Linux服务器进行文件互传)和其他网络服务提供安全性的协议&#xff0c;可有效弥补网络中的漏洞。通…

Java预科知识

以下内容是根据狂神的Java说、chatgpt和csdn相关博客&#xff0c;结合自己的理解完成的。 Java了解 基于Java 开发了巨多的平台&#xff0c;系统&#xff0c;工具 构建工具&#xff1a; Ant, Maven, Jekins应用服务器&#xff1a;Tomcat, Jetty, Jboss, Websphere, weblogic…

vue的data

类型&#xff1a;Object | Function 限制&#xff1a;组件的定义只接受 function。 详细&#xff1a; Vue 实例的数据对象。Vue 会递归地把 data 的 property 转换为 getter/setter&#xff0c;从而让 data 的 property 能够响应数据变化。对象必须是纯粹的对象 (含有零个或多个…