FastAPI学习-23.异常处理器 exception_handler

news/2024/11/8 9:00:03/

前言

通常我们可以通过 raise 抛出一个 HTTPException 异常,请求参数不合法会抛出RequestValidationError 异常,这是最常见的2种异常。

HTTPException 异常

向客户端返回 HTTP 错误响应,可以使用 raise 触发 HTTPException

from fastapi import FastAPI, HTTPExceptionapp = FastAPI()@app.get("/path/{name}")  
async def read_unicorn(name: str):  if name == "yoyo":  raise HTTPException(404, detail=f"name: {name} not found")  return {"path_name": name}

默认情况下返回json格式

HTTP/1.1 404 Not Found
date: Wed, 27 Sep 2023 02:07:07 GMT
server: uvicorn
content-length: 22
content-type: application/json{"detail":"Not Found"}

覆盖默认的HTTPException 异常

查看HTTPException 异常相关源码

from starlette.exceptions import HTTPException as StarletteHTTPException  class HTTPException(StarletteHTTPException):  def __init__(  self,  status_code: int,  detail: Any = None,  headers: Optional[Dict[str, Any]] = None,  ) -> None:  super().__init__(status_code=status_code, detail=detail, headers=headers)

HTTPException 异常是继承的 starlette 包里面的 HTTPException
覆盖默认异常处理器时需要导入 from starlette.exceptions import HTTPException as StarletteHTTPException,并用 @app.excption_handler(StarletteHTTPException) 装饰异常处理器。

from fastapi import FastAPI, Request  
from fastapi.exceptions import HTTPException  
from fastapi.responses import PlainTextResponse, JSONResponse  
from starlette.exceptions import HTTPException as StarletteHTTPException  app = FastAPI()  # # 捕获 HTTPException 异常  
@app.exception_handler(StarletteHTTPException)  
def http_error(request, exc):  print(exc.status_code)  print(exc.detail)  # return JSONResponse({'error_msg': exc.detail}, status_code=exc.status_code)  return PlainTextResponse(content=exc.detail, status_code=exc.status_code)  @app.get("/path/{name}")  
async def read_unicorn(name: str):  if name == "yoyo":  raise HTTPException(404, detail=f"name: {name} not found")  return {"path_name": name}

这样原来的 HTTPException 返回 json 格式,现在改成返回text/plain 文本格式了。

HTTP/1.1 404 Not Found
date: Wed, 27 Sep 2023 07:24:58 GMT
server: uvicorn
content-length: 20
content-type: text/plain; charset=utf-8name: yoyo not found

覆盖请求验证异常

请求中包含无效数据时,FastAPI 内部会触发 RequestValidationError
该异常也内置了默认异常处理器。

覆盖默认异常处理器时需要导入 RequestValidationError,并用 @app.excption_handler(RequestValidationError) 装饰异常处理器。

这样,异常处理器就可以接收 Request 与异常。

from fastapi import FastAPI, HTTPException
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
from starlette.exceptions import HTTPException as StarletteHTTPExceptionapp = FastAPI()@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):return PlainTextResponse(str(exc), status_code=400)@app.get("/items/{item_id}")
async def read_item(item_id: int):if item_id == 3:raise HTTPException(status_code=418, detail="Nope! I don't like 3.")return {"item_id": item_id}

访问 /items/foo,可以看到以下内容替换了默认 JSON 错误信息:

{"detail": [{"loc": ["path","item_id"],"msg": "value is not a valid integer","type": "type_error.integer"}]
}

以下是文本格式的错误信息:

HTTP/1.1 400 Bad Request
date: Wed, 27 Sep 2023 07:30:38 GMT
server: uvicorn
content-length: 103
content-type: text/plain; charset=utf-81 validation error for Request
path -> item_idvalue is not a valid integer (type=type_error.integer)

RequestValidationError 源码分析

RequestValidationError 相关源码

class RequestValidationError(ValidationError):  def __init__(self, errors: Sequence[ErrorList], *, body: Any = None) -> None:  self.body = body  super().__init__(errors, RequestErrorModel)

使用示例

from fastapi import FastAPI, Request, status
from fastapi.encoders import jsonable_encoder
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from pydantic import BaseModelapp = FastAPI()@app.exception_handler(RequestValidationError)  
async def validation_exception_handler(request: Request, exc: RequestValidationError):  print(exc.json())  print(exc.errors())  print(exc.body)   # 请求body  return JSONResponse(  status_code=400,  content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),  )  class Item(BaseModel):  title: str  size: int  @app.post("/items/")  
async def create_item(item: Item):  return item

现在试着发送一个无效的 item,例如:

{"title": "towel","size": "XL"
}

运行结果

HTTP/1.1 400 Bad Request
date: Wed, 27 Sep 2023 07:51:36 GMT
server: uvicorn
content-length: 138
content-type: application/json{"detail":[{"loc":["body","size"],"msg":"value is not a valid integer","type":"type_error.integer"}],"body":{"title":"towel","size":"XL"}}

RequestValidationError 和 ValidationError

如果您觉得现在还用不到以下技术细节,可以先跳过下面的内容。

RequestValidationError 是 Pydantic 的 ValidationError的子类。

FastAPI 调用的就是 RequestValidationError 类,因此,如果在 response_model 中使用 Pydantic 模型,且数据有错误时,在日志中就会看到这个错误。

但客户端或用户看不到这个错误。反之,客户端接收到的是 HTTP 状态码为 500 的「内部服务器错误」。

这是因为在_响应_或代码(不是在客户端的请求里)中出现的 Pydantic ValidationError 是代码的 bug。

修复错误时,客户端或用户不能访问错误的内部信息,否则会造成安全隐患。


http://www.ppmy.cn/news/1140170.html

相关文章

LCR 133.位 1 的个数

​​题目来源: leetcode题目,网址:LCR 133. 位 1 的个数 - 力扣(LeetCode) 解题思路: 重复利用 n&(n-1) 将 n 最右边一个 1 消除直至 n 为 0,返回循环次数即可。 解题代码: p…

论文阅读-- A simple transmit diversity technique for wireless communications

一种简单的无线通信发射分集技术 论文信息: Alamouti S M. A simple transmit diversity technique for wireless communications[J]. IEEE Journal on selected areas in communications, 1998, 16(8): 1451-1458. 创新性: 提出了一种新的发射分集方…

ESP32设备驱动-TFT_eSPI显示中文

TFT_eSPI显示中文 文章目录 TFT_eSPI显示中文1、安装TFT_eSPI库2、创建字库3、生成字库头文件4、使用字库本文将详细介绍如何使用TFT_eSPI显示中文。 1、安装TFT_eSPI库 2、创建字库 TFT_eSPI字体工具使用Processing软件创建字体。 下载并安装Processing:https://processin…

C++ 提示并输入一个字符串,统计该字符中大写、小写字母个数、数字个数、空格个数以及其他字符个数

#include <iostream>using namespace std;int main() {string str;cout << "请输入一个字符串>>>" << endl;getline(cin, str);int size str.size();int xiaoxie 0;int daxie 0;int shuzi 0;int kongge 0;int qita 0;for(int i0;i < …

机器视觉工程师,公司设置奖金,真的为了奖励你吗?其实和你没关系

​据说某家大厂&#xff0c;超额罚款&#xff0c;有奖有罚很正常&#xff0c;但是我觉得你罚款代理商员工就不一样了&#xff0c;把代理商当成你的员工&#xff0c;我就觉得这些大厂的脑回路有问题。 有人从来没听说过项目奖金&#xff0c;更没有奖金。那么为什么设置奖金呢&a…

nginx的配置文件概述及简单demo(二)

默认配置文件 当安装完nginx后&#xff0c;它的目录下通常有默认的配置文件 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connection…

Mybatis整理

Mybatis 定义 Mybatis是一个半ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;加载驱动、创建连接、创建statement等繁杂的过程&#xff0c;开发者开发时只需要关注如何编写SQL语句&#xff0c;可以严格控制sql执行性能&#xff0c;灵…

【GIT版本控制】--项目管理与工具

一、使用Git与项目管理工具的集成 将Git与项目管理工具集成在一起可以有效地跟踪和管理软件开发项目。以下是如何使用Git与项目管理工具&#xff08;如GitHub、GitLab、Bitbucket和Jira&#xff09;进行集成的关键方法&#xff1a; 创建问题或任务&#xff1a; 项目管理工具通…