Skip to content

异常

Starlette 允许您安装自定义异常处理程序,以处理在发生错误或已处理的异常时如何返回响应。

from starlette.applications import Starlette
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import HTMLResponse


HTML_404_PAGE = ...
HTML_500_PAGE = ...


async def not_found(request: Request, exc: HTTPException):
    return HTMLResponse(content=HTML_404_PAGE, status_code=exc.status_code)

async def server_error(request: Request, exc: HTTPException):
    return HTMLResponse(content=HTML_500_PAGE, status_code=exc.status_code)


exception_handlers = {
    404: not_found,
    500: server_error
}

app = Starlette(routes=routes, exception_handlers=exception_handlers)

如果 debug 已启用且发生错误,则 Starlette 将使用回溯响应,而不是使用已安装的 500 处理程序。

app = Starlette(debug=True, routes=routes, exception_handlers=exception_handlers)

除了为特定的状态码注册处理程序外,您还可以为异常类注册处理程序。

特别是您可能想要覆盖内置的 HTTPException 类的处理方式。例如,使用 JSON 风格的响应:

async def http_exception(request: Request, exc: HTTPException):
    return JSONResponse({"detail": exc.detail}, status_code=exc.status_code)

exception_handlers = {
    HTTPException: http_exception
}

HTTPException 还配备了 headers 参数。这允许将标头传播到响应类:

async def http_exception(request: Request, exc: HTTPException):
    return JSONResponse(
        {"detail": exc.detail},
        status_code=exc.status_code,
        headers=exc.headers
    )

您可能还想要覆盖 WebSocketException 的处理方式:

async def websocket_exception(websocket: WebSocket, exc: WebSocketException):
    await websocket.close(code=1008)

exception_handlers = {
    WebSocketException: websocket_exception
}

错误和已处理的异常

区分已处理的异常和错误是很重要的。

已处理的异常并不代表错误情况。它们被强制转换为适当的 HTTP 响应,然后通过标准中间件栈发送。默认情况下,使用 HTTPException 类来管理任何已处理的异常。

错误是应用程序内发生的任何其他异常。这些情况应作为异常在整个中间件堆栈中冒泡。任何错误日志记录中间件都应确保将异常一路重新引发到服务器。

实际上,所使用的错误处理为 exception_handler[500]exception_handler[Exception]500Exception 这两个键均可使用。见下文:

async def handle_error(request: Request, exc: HTTPException):
    # Perform some logic
    return JSONResponse({"detail": exc.detail}, status_code=exc.status_code)

exception_handlers = {
    Exception: handle_error  # or "500: handle_error"
}

需要注意的是,如果 BackgroundTask 引发异常,将由 handle_error 函数进行处理,但此时响应已经发送。换句话说, handle_error 创建的响应将被丢弃。如果错误发生在响应发送之前,那么将使用响应对象 - 在上述示例中,为返回的 JSONResponse

为了正确处理这种行为, Starlette 应用程序的中间件堆栈是这样配置的:

  • ServerErrorMiddleware - 当服务器出现错误时返回 500 个响应。
  • 已安装的中间件
  • ExceptionMiddleware - 处理已处理的异常,并返回响应。
  • 路由器
  • 端点

HTTP 异常

HTTPException 类提供了一个基类,您可以将其用于任何已处理的异常。 ExceptionMiddleware 的实现默认对于任何 HTTPException 都返回纯文本 HTTP 响应。

  • HTTPException(status_code, detail=None, headers=None)

您应该仅在路由或端点内部引发 HTTPException 。相反,中间件类应该直接返回适当的响应。

WebSocket 异常

您可以使用 WebSocketException 类在 WebSocket 端点内部引发错误。

  • WebSocketException(code=1008, reason=None)

您可以设置规范中定义的任何有效代码。