前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >FastAPI后台开发基础(13): 异常处理 Exception

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

原创
作者头像
bowenerchen
发布2024-11-01 10:06:04
700
发布2024-11-01 10:06:04
举报
文章被收录于专栏:编码视界

异常的捕获

代码语言:python
代码运行次数:0
复制
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
复制
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
复制
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
复制
@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
复制
@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
复制
@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
复制
@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
复制
@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
复制
@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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 异常的捕获
  • 自定义异常
    • 自定义异常处理:提升FastAPI应用的健壮性与用户体验
      • 定义自定义异常
        • 异常处理装饰器
          • 触发自定义异常
          • 异常的重载
            • 异常重载基础
              • 验证异常处理
                • 异常处理实践
                  • 异常处理的继承和查找
                  相关产品与服务
                  云服务器
                  云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档