首页 > 其他分享 > FastAPI学习-23.异常处理器 exception_handler

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

时间:2023-09-29 09:44:51浏览次数:38  
标签:exception name HTTPException 23 FastAPI app RequestValidationError import exc

前言

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

HTTPException 异常

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

from fastapi import FastAPI, HTTPException

app = 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-8

name: 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 StarletteHTTPException

app = 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-8

1 validation error for Request
path -> item_id
  value 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 BaseModel

app = 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。

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

标签:exception,name,HTTPException,23,FastAPI,app,RequestValidationError,import,exc
From: https://www.cnblogs.com/yoyoketang/p/17736791.html

相关文章

  • FastAPI学习-24.自定义异常处理器 exception_handler
    前言添加自定义处理器,要使用 Starlette的异常工具。安装自定义异常处理器假设要触发的自定义异常叫作 UnicornException。且需要FastAPI实现全局处理该异常。此时,可以用 @app.exception_handler() 添加自定义异常控制器:fromfastapiimportFastAPI,Requestfromfa......
  • FastAPI学习-25.response_model 定义响应模型
    你可以在任意的_路径操作_中使用 response_model 参数来声明用于响应的模型:@app.get()@app.post()@app.put()@app.delete()fromtypingimportAny,List,UnionfromfastapiimportFastAPIfrompydanticimportBaseModelapp=FastAPI()classItem(BaseModel)......
  • 2023.09.28
    给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。每个右括号都有一个对应的相同类型的左括号。 示例1:输入:s="()"输出:true示例 2:输入:s="()[]{}"输出:t......
  • 2023.09.26 动手动脑
    Java的类在构造时会提供一个无参的构造方法,如果已存在用户已经自定义的构造方法,则原有的无参构造方法将无法调用,只能调用自己定义的构造方法。静态初始化的执行顺序:classRoot{static{System.out.println("Root的静态初始化块");}{Sys......
  • 2023.9.28
    今天是在做一道buuctf上的题目,但是过程中遇到了一些困难,写这篇随笔的时候还没能解决,打算明天继续去问学长对了,昨天想试的一些东西试玩了,主要是关于一些调试和libc获取方面的东西在家里学习感觉还是和在学校不一样,感觉在家里学习学着学着就会想躺床上去,在学校嫌爬上爬下的麻烦就......
  • 236 中秋前一天
    9-28,中秋前一天,刚开学不久,还不怎么想家。明儿主动给家里打电话还是必要的今天很是普通。下午两节课,都收获不大。晚上物联网课还得是靠自己,虽然我是打了两节课的保卫萝卜晚上回来有学习,优化了昨天的学生通讯录程序代码,看了一眼航空订票系统项目,明儿开动应该。今天就这样咯。......
  • 2023.9.27测试
    \[\text{省流:1.5h狂砍8分}\]T1[ABC311F]YetAnotherGridTaskwhat??发现一个点染了黑色后它下面会将一个三角形染成黑色,画个图发现按列考虑比较好设\(f_{i,j}\)表示第\(i\)列最高的黑色格子为第\(j\)行的,\(j=n+1\)表示这一列全是白色。那么有转移\[f_{i,j}=\sum_{k=j......
  • CSP-J/S 2023 游记
    \(9.16\)初赛。\(9:00\)就到了振万教学楼,休息了一下,准备去\(5\)楼考场。\(9:05\)到了考场门口,发现教室里面已经开了空调,但xxs们都不进去,6。于是我第一个进了考场。\(9:30\)总算看到试题卷了,好像除了第\(4,10\)题都很简单。\(10:20\)做完了卷子,开始检查。\(11:30\)......
  • 2023icpc第二场网络赛c
    做法2-sat赛时想到了2sat+前缀和优化,但是对于每个点都要覆盖到脑袋抽了没想出来怎么建边对于一个点如果他没被选择那么他的前一个点和后一个点是必选的,然后就是一道非常裸的2sat+前缀和优化 P6378[PA2010]Riddle(模板题)1这个点是必选的,n这个点是必定不选的#includ......
  • 2023年9月28日(动手动脑)
    PublicclassTese{pulicstaticvoifmain(String[]args){Fooobj1=newFoo();}classFoo{intvalue;publicFoo(intinitValue){value=initValue;}}}以上代码在编译时会出现错误,原因是因为如果类提供了一个自定义的构造方法,将导致系统不再提高默认构造方法。而对......