Exceptions
Starlette allows you to install custom exception handlers to handle how responses are returned when errors or handled exceptions occur.
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)
If debug is enabled and an error occurs, Starlette uses a backtracking response instead of using an installed 500 handler.
app = Starlette(debug=True, routes=routes, exception_handlers=exception_handlers)
In addition to registering handlers for specific status codes, you can also register handlers for exception classes.
In particular, you may want to override how the built-in HTTPException class is handled. For example, use JSON-style responses:
async def http_exception(request: Request, exc: HTTPException):
return JSONResponse({"detail": exc.detail}, status_code=exc.status_code)
exception_handlers = {
HTTPException: http_exception
}
HTTPException also comes with the headers parameter. This allows the header to be propagated to the response class:
async def http_exception(request: Request, exc: HTTPException):
return JSONResponse(
{"detail": exc.detail},
status_code=exc.status_code,
headers=exc.headers
)
You may also want to override how WebSocketException is handled:
async def websocket_exception(websocket: WebSocket, exc: WebSocketException):
await websocket.close(code=1008)
exception_handlers = {
WebSocketException: websocket_exception
}
Errors and handled exceptions
It is important to distinguish handled exceptions from errors.
Handled exceptions do not represent error conditions. They are coerced into appropriate HTTP responses and sent through the standard middleware stack. By default, the HTTPException class is used to manage any handled exceptions.
Errors are any other exceptions that occur within the application. These should bubble through the middleware stack as exceptions. Any error logging middleware should ensure that exceptions are rethrown all the way to the server.
In fact, the error handler used is exception_handler[500] or exception_handler[Exception]. Both 500 and Exception keys can be used. See below:
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"
}
It is important to note that if BackgroundTask Exception thrown, will be handle_error Function, but the response has already been sent. In other words, handle_error The created response is discarded. If the error occurs before the response is sent, the response object is used-in the example above, the returned JSONResponse 。
To properly handle this behavior, the middleware stack of the Starlette application is configured as follows:
ServerErrorMiddleware- Returns 500 responses when the server encounters an error.- Installed middleware
ExceptionMiddleware- Handles handled exceptions and returns a response.- Router
- endpoint
HTTP exception
The HTTPException class provides a base class that you can use for any handled exception. The implementation of ExceptionMiddleware returns a plain text HTTP response by default for any HTTPException.
HTTPException(status_code, detail=None, headers=None)
You should raise HTTPException only inside routes or endpoints. Instead, middleware classes should return the appropriate response directly.
WebSocket exception
You can use the WebSocketException class to raise errors inside the WebSocket endpoint.
WebSocketException(code=1008, reason=None)
You can set any valid code defined in the specification.