Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >FastAPI后台开发基础(13): 异常处理 Exception

FastAPI后台开发基础(13): 异常处理 Exception

原创
作者头像
密码学人CipherHUB
发布于 2024-11-01 02:06:04
发布于 2024-11-01 02:06:04
28200
代码可运行
举报
文章被收录于专栏:编码视界编码视界
运行总次数:0
代码可运行

异常的捕获

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
items = {"foo": "The Foo Wrestlers"}


@app.get("/items/{item_id}")
async def read_item(item_id: str):
    """
    the in operator for dictionaries checks if the given key exists in the dictionary
    in items is slightly more efficient because it directly uses the dictionary's hash table for lookup
    the items.keys() method is more useful when you need to perform operations on the keys themselves,
    such as set operations or when you need to pass the keys to another function
        common_keys = set(items.keys()) & set(other_dict.keys())
    """
    if item_id not in items:
        """
        The situation with HTTP headers and character encoding is a bit nuanced:
        Header Names: These should always be ASCII characters. 
                      This is a strict requirement in the HTTP specification.
        Header Values: The HTTP/1.1 specification (RFC 7230) states that header field values may contain 
                       any character from the ASCII character set, except for a few specific control characters. 
                       However, non-ASCII characters (like Chinese characters) are not directly supported in header values.
        Practical Implementation: Many modern web servers and clients can handle non-ASCII characters in header values, 
                                  but this is not guaranteed to work universally. 
                                  It may cause issues with some servers, proxies, or other intermediaries.
        Best Practices: To ensure maximum compatibility and adherence to standards, 
                        it's recommended to restrict header values to ASCII characters. 
                        When you need to include non-ASCII content, 
                        you should encode it (using methods like URL encoding, Base64, etc.) as we discussed earlier.
        """
        raise HTTPException(status_code = 404,
                            detail = "Item not found",
                            headers = {
                                "my-header": quote("this is my header error info 中文信息"),
                                "Content-Type": "application/json; charset=utf-8"
                            })
    return {"item": items[item_id]}

通过raise HTTPException抛出一个异常,这个异常不仅设置了HTTP状态码为404,表示“未找到”,还详细描述了错误信息“Item not found”。此外,我们还在响应头中设置了自定义的my-header和Content-Type,后者指定了响应内容的类型和字符集。

在设置HTTP头时,我们需要考虑字符编码的问题。根据HTTP规范,头部名称必须是ASCII字符,而头部值可以包含ASCII字符集中的任何字符,除了一些特定的控制字符。虽然现代的Web服务器和客户端可以处理非ASCII字符,但这并不是普遍支持的,可能会导致与某些服务器或代理的兼容性问题。因此,为了确保最大的兼容性和遵守标准,建议将头部值限制为ASCII字符。如果需要包含非ASCII内容,应该进行编码,比如使用URL编码或Base64。

捕获异常
捕获异常

自定义异常

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class MyException(Exception):
    def __init__(self):
        self.occurred_time = datetime.datetime.now().isoformat()
        self.uuid = uuid.uuid4().hex


@app.exception_handler(MyException)
def my_exception_handler(request: Request, exc: MyException):
    return JSONResponse(
        status_code = http.HTTPStatus.BAD_REQUEST,
        content = {
            'exception_occurred_time': exc.occurred_time,
            'exception_uuid': exc.uuid,
            'method': request.method,
            'url': f'{request.url.scheme}://{request.url.hostname}:{request.url.port}{request.url.path}',
            'headers': dict(request.headers.items()),
        })


@app.post('/raise_my_exception/{test_id}')
def raise_my_exception(test_id: str, req: Request):
    if test_id == 'raise':
        raise MyException()
    else:
        return JSONResponse(
            status_code = http.HTTPStatus.OK,
            content = {
                'url': f'{req.url.scheme}://{req.url.hostname}:{req.url.port}{req.url.path}',
                'method': req.method,
                'headers': dict(req.headers.items()),
            }
        )

自定义异常处理:提升FastAPI应用的健壮性与用户体验

在构建Web应用时,异常处理是一个关键环节,它不仅关系到应用的稳定性,也直接影响到用户体验。FastAPI作为一个现代、快速(高性能)的Web框架,提供了强大的异常处理机制,允许开发者自定义异常,从而更精细地控制错误响应。本文将通过一个实际的例子,展示如何在FastAPI中实现自定义异常处理。

定义自定义异常

首先,我们定义了一个名为MyException的自定义异常类,它继承自Python的基类Exception。在初始化方法__init__中,我们记录了异常发生的时间(使用ISO格式),并为每个异常实例生成了一个唯一的UUID。这两个属性将用于后续的错误响应中,以提供详细的错误信息。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
class MyException(Exception):
    def __init__(self):
        self.occurred_time = datetime.datetime.now().isoformat()
        self.uuid = uuid.uuid4().hex

异常处理装饰器

接下来,我们使用@app.exception_handler装饰器来定义一个异常处理器。这个处理器专门用来处理MyException类型的异常。当MyException被抛出时,FastAPI将调用这个处理器,并传入请求对象和异常对象。处理器返回一个JSONResponse对象,其中包含了异常发生的时间、UUID、请求方法、URL以及请求头等信息。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
@app.exception_handler(MyException)
def my_exception_handler(request: Request, exc: MyException):
    return JSONResponse(
        status_code = http.HTTPStatus.BAD_REQUEST,
        content = {
            'exception_occurred_time': exc.occurred_time,
            'exception_uuid': exc.uuid,
            'method': request.method,
            'url': f'{request.url.scheme}://{request.url.hostname}:{request.url.port}{request.url.path}',
            'headers': dict(request.headers.items()),
        }
    )

触发自定义异常

在实际的路由处理函数中,我们可以根据业务逻辑抛出MyException。例如,当POST请求的test_id参数为'raise'时,我们抛出MyException,触发自定义的异常处理流程。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
@app.post('/raise_my_exception/{test_id}')
def raise_my_exception(test_id: str, req: Request):
    if test_id == 'raise':
        raise MyException()
    else:
        return JSONResponse(
            status_code = http.HTTPStatus.OK,
            content = {
                'url': f'{req.url.scheme}://{req.url.hostname}:{req.url.port}{req.url.path}',
                'method': req.method,
                'headers': dict(req.headers.items()),
            }
        )
自定义异常
自定义异常

异常的重载

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    """
        HTTPException is a subclass of StarletteHTTPException
        so when you raise an HTTPException
        it's caught by the StarletteHTTPException handler
    """
    return PlainTextResponse(str(f'http_exception_handler, '
                                 f'this is my http exception info:{exc.detail}, '
                                 f'req headers: {request.headers}'
                                 f'req url: {request.url.path}'),
                             status_code = exc.status_code)


@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    """
        RequestValidationError is a specific exception raised by Pydantic when request validation fails
        It's caught by the RequestValidationError handler
        the custom ValidationException doesn't work with the RequestValidationError handler (they're unrelated)

        when you raise an exception
        FastAPI looks for the most specific matching exception handler
        If it doesn't find one
        it moves up the exception hierarchy
        until it finds a suitable handler
        or reaches the default exception handling behavior.

        FastAPI doesn't have a built-in exception class specifically named "ValidationException".
        Instead, it primarily uses the following exception classes for validation-related issues:
            RequestValidationError: This is raised when the incoming request data fails validation against the defined model or parameters.
                                    It's part of FastAPI and is raised automatically when request data doesn't match the expected schema.

            ValidationError: This is a Pydantic exception, which FastAPI uses internally.
                             It's raised when data fails validation against a Pydantic model.
    """
    return PlainTextResponse(str(f'validation_exception_handler, '
                                 f'this is my validation exception info: {exc.errors()},'
                                 f'req headers: {request.headers},'
                                 f'req url: {request.url.path},'
                                 f'body: {exc.body}'),
                             status_code = 400)


@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 0:
        raise HTTPException(status_code = 418, detail = f'item_id is {item_id}')
    if item_id == 1:
        """
        curl -X 'GET' 'http://127.0.0.1:18081/items/abc' -H 'accept: application/json'
        """
        raise RequestValidationError(errors = ['ABC', 'DEF'])
    return {"item_id": item_id}


class Item(BaseModel):
    title: str
    size: int


@app.post("/items/")
async def create_item(item: Item):
    return item

异常重载基础

在FastAPI中,HTTPExceptionStarletteHTTPException的子类,这意味着当你抛出一个HTTPException时,它会被StarletteHTTPException的处理程序捕获。这种机制允许开发者为特定类型的HTTP异常定义统一的处理逻辑。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
@app.exception_handler(StarletteHTTPException)
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
    return PlainTextResponse(
        str(f'http_exception_handler, this is my http exception info:{exc.detail}, req headers: {request.headers} req url: {request.url.path}'),
        status_code=exc.status_code
    )

验证异常处理

FastAPI使用RequestValidationError来处理请求验证失败的情况,这是Pydantic在请求数据不符合预期模式时自动抛出的异常。开发者可以为这个异常定义一个处理器,以提供更详细的错误信息。

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    return PlainTextResponse(
        str(f'validation_exception_handler, this is my validation exception info: {exc.errors()}, req headers: {request.headers}, req url: {request.url.path}, body: {exc.body}'),
        status_code=400
    )

异常处理实践

在实际的路由处理中,开发者可以根据业务逻辑抛出不同的异常。例如,如果item_id为0,可以抛出一个HTTPException;如果item_id为1,可以抛出一个RequestValidationError

代码语言:python
代码运行次数:0
运行
AI代码解释
复制
@app.get("/items/{item_id}")
async def read_item(item_id: int):
    if item_id == 0:
        raise HTTPException(status_code=418, detail=f'item_id is {item_id}')
    if item_id == 1:
        raise RequestValidationError(errors=['ABC', 'DEF'])
    return {"item_id": item_id}

异常处理的继承和查找

FastAPI在处理异常时,会从最具体的异常类型开始查找匹配的处理程序。如果没有找到,它会沿着异常继承体系向上查找,直到找到一个合适的处理器或到达默认的异常处理行为。这种机制使得FastAPI的异常处理既灵活又强大。

重载异常 1
重载异常 1
重载异常 2
重载异常 2
重载异常 3
重载异常 3

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
FastAPI官方教程太棒了(下)
status_code也可以是IntEnum,比如Python的http.HTTPStatus。
dongfanger
2022/11/21
2.7K0
FastAPI官方教程太棒了(下)
FastAPI--中间件(6)
所谓的中间件,其实和我们bottle中的中间件作用是一致。有些方法或操作需要在所有路由之前执行,比如要加一个http访问的拦截器,可以对部分接口API需要授权才能访问的接口进行验证之类的。
py3study
2020/06/30
1.6K0
FastAPI--中间件(6)
FastAPI--错误处理(5)
再之前Bottle 中其实有一个就是HttpError异常类,在FastAPI也存在这么一个HTTPException。比如:
py3study
2020/06/28
1.4K0
【云+社区年度征文】全面拥抱FastApi-优雅的处理HTTPException
众所周知,因客户端或调用方的原因导致出错的,返回的状态码是以 4 开头的 (400~499)
Python编程与实战
2020/12/21
1.8K1
【云+社区年度征文】全面拥抱FastApi-优雅的处理HTTPException
FastAPI从入门到实战(12)——错误处理
定义一个Exception类型错误类UnicornException,在实际应用中就对应登录失败错误、验证码错误等;
MinChess
2022/12/27
1.8K0
FastAPI从入门到实战(12)——错误处理
(进阶篇)Python web框架FastAPI——一个比Flask和Tornada更高性能的API 框架
上一篇已经初步了解了 FastAPI 的基本使用,但是如果想要真正把 FastAPI 部署上线到服务器,那么你需要了解更多,学习更多。所以本篇内容将注重于 FastAPI 的项目生产环境,诸如 数据库,路由蓝图,数据验证等问题在 FastAPI 中的具体操作和一些自己碰到的坑,分享给正在进攻 FastAPI 的各位小伙伴。
Python进阶者
2020/04/08
2.7K0
(进阶篇)Python web框架FastAPI——一个比Flask和Tornada更高性能的API 框架
fastapi 请求文件 / 表单 / 处理错误 / 路径操作配置 / jsonable_encoder
learn from https://fastapi.tiangolo.com/zh/tutorial/request-files/
Michael阿明
2022/01/07
1.2K0
fastapi 请求文件 / 表单 / 处理错误 / 路径操作配置 / jsonable_encoder
FastAPI(43)- 基于 pytest + requests 进行单元测试
https://www.cnblogs.com/poloyy/tag/Pytest/
小菠萝测试笔记
2021/10/09
1.8K0
FastAPI(43)- 基于 pytest + requests 进行单元测试
python的FastAPI, 你了解多少?
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.8+ 并基于标准的 Python 类型提示。
shengjk1
2025/05/16
960
python的FastAPI, 你了解多少?
高效优雅处理程序错误实战
今天,讨论一下程序中的错误处理。也许你会觉得这个事没什么意思,处理错误的代码并不难写。但你想过没有,要把错误处理写好,并不是件容易的事情。另外,任何一个稳定的程序中都会有大量的代码在处理错误,所以说,处理错误是程序中一件比较重要的事情。本篇我们系统地了解一下错误处理的各种方式和相关实践。
python编程从入门到实践
2021/03/29
9560
高效优雅处理程序错误实战
python的FastAPI 快速入门
最近在做公司内部的RAG,也就是基于大模型的检索增强,专门针对公司内部的私有化数据。在这个过程中,使用了 FastAPI 来做整个 服务端 的开发。接下来我们就整体了解一下 FastAPI,争取做到基本入门
shengjk1
2025/05/16
1710
python的FastAPI 快速入门
FastAPI 学习之路(十九)处理错误
4XX 状态码与表示请求成功的 2XX(200 至 299) HTTP 状态码类似。
雷子
2021/08/25
1.1K0
全面拥抱FastApi — 蓝图APIRouter
我们都知道在大型的应用程序或者 web api 中, 我们很少在一个文件中写入多个路由
Python编程与实战
2021/02/08
1.7K0
FastAPI从入门到实战(13)——常见配置项
九陌斋地址:https://blog.jiumoz.com/archives/fastapi-cong-ru-men-dao-shi-zhan-13-chang-jian-pei-zhi-xiang
MinChess
2022/12/27
1.9K0
FastAPI从入门到实战(13)——常见配置项
FastAPI后台开发基础(17): Middleware 的使用
密码学人CipherHUB
2024/11/19
2660
FastAPI后台开发基础(17): Middleware 的使用
FastAPI后台开发基础(15): 依赖注入
在 FastAPI 中,依赖项可以是任何可调用的对象,如函数、类方法等。这些依赖项可以接受参数,这些参数同样可以是其他依赖项,从而形成依赖关系链。FastAPI 会自动处理这些依赖关系,确保在调用主功能(如API路由处理函数)之前,所有依赖项都已正确解析和调用。
密码学人CipherHUB
2024/11/18
3531
FastAPI后台开发基础(15): 依赖注入
FastAPI学习-10. 路由管理APIRouter
在 Flask 中,我们一般用蓝图 Blueprint 来处理多个模块的视图,在fastapi 中也有类似的功能通过APIRouter 来管理。
上海-悠悠
2023/09/21
9000
FastAPI学习-10. 路由管理APIRouter
FastAPI(59)- 详解使用 OAuth2PasswordBearer + JWT 认证
需要安装 python-jose 来在 Python 中生成和验证 JWT token
小菠萝测试笔记
2021/10/09
1.9K0
FastAPI(59)- 详解使用 OAuth2PasswordBearer + JWT 认证
Python面试:FastAPI框架原理与实战
FastAPI,作为近年来快速崛起的高性能Python Web框架,以其简洁的API设计、强大的类型提示支持、出色的文档生成能力以及对现代Web开发标准的紧密遵循,赢得了广大开发者的青睐。在Python面试中,对FastAPI的理解与实践能力已成为评估候选人技能的重要组成部分。本篇博客将深入浅出地探讨FastAPI面试中常见的问题、易错点以及应对策略,并结合实例代码进行讲解。
Jimaks
2024/04/21
5850
FastAPI(27)- Handling Errors 处理错误
当请求包含无效数据时,FastAPI 会在内部引发 RequestValidationError,它还包括一个默认的异常处理程序
小菠萝测试笔记
2021/09/27
1.2K0
推荐阅读
相关推荐
FastAPI官方教程太棒了(下)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验