如何制作自定义404页面?

How to make a custom 404 page?

我正在为 Discord 创建一个 rick roll 网站,我想在 404 响应状态代码上重定向到 rick roll 页面。

我试过以下方法,但没有用:

 @app.exception_handler(fastapi.HTTPException)
 async def http_exception_handler(request, exc):
     ...

您需要创建一个 middleware and check for the status_code of the response. If it is 404, then return a RedirectResponse。示例:

from fastapi import Request
from fastapi.responses import RedirectResponse

@app.middleware("http")
async def redirect_on_not_found(request: Request, call_next):
    response = await call_next(request)
    if response.status_code == 404:
        return RedirectResponse("https://fastapi.tiangolo.com")
    else:
        return response
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException

# --- Constants --- #

templates = Jinja2Templates(directory="./templates")

# --- Error handler --- #

def lost_page(request, exception):
    headers = {"Content-Type": "text/html"}

    if isinstance(exception, HTTPException):
        status_code = exception.status_code
        detail = exception.detail
    elif isinstance(exception, Exception):
        status_code = 500
        detail = "Server Error"
        headers["X-Error-Message"] = exception.__class__.__name__
        headers["X-Error-Line"] = str(exception.__traceback__.tb_lineno)
    else:
        status_code = 500
        detail = f"Server Error\n\nDetails: {exception}"

    return templates.TemplateResponse(
        "404.html",
        {"request": request, "status_code": status_code, "detail": detail},
        status_code=status_code,
        headers=headers,
    )


exception_handlers = {num: lost_page for num in range(400, 599)}
app = FastAPI(exception_handlers=exception_handlers)

这是我在几个项目中使用的一个片段,它本质上是一个 catch-all 用于所有 400 和 500 状态代码。

from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException

# --- Constants --- #

templates = Jinja2Templates(directory="./templates")

此块导入相关库并初始化 Jinja2Templates,这允许我们使用 FastAPI 渲染 HTML。 Docs.

来剖析一下

def lost_page(request, exception):
    headers = {"Content-Type": "text/html"}

    if isinstance(exception, HTTPException):
        status_code = exception.status_code
        detail = exception.detail
    elif isinstance(exception, Exception):
        status_code = 500
        detail = "Server Error"
        headers["X-Error-Message"] = exception.__class__.__name__
        headers["X-Error-Line"] = str(exception.__traceback__.tb_lineno)
    else:
        status_code = 500
        detail = f"Server Error\n\nDetails: {exception}"

    return templates.TemplateResponse(
        "404.html",
        {"request": request, "status_code": status_code, "detail": detail},
        status_code=status_code,
        headers=headers,
    )

FastAPI 的异常处理程序提供两个参数,导致异常的请求 object 和引发的异常。

def lost_page(request, exception):

^^ 我们的函数接受这两个参数。

headers = {"Content-Type": "text/html"}

这些是我们将随请求一起发回的 headers。

    if isinstance(exception, HTTPException):
        status_code = exception.status_code
        detail = exception.detail

    elif isinstance(exception, Exception):
        status_code = 500
        detail = "Server Error"
        headers["X-Error-Name"] = exception.__class__.__name__

    else:
        status_code = 500
        detail = f"Server Error\n\nDetails: {exception}"

如果 exception 参数是 HTTPException(由 Starlette/FastAPI 引发),那么我们将适当地设置 status_code 和详细信息。 HTTPException 的一个示例是 404 错误,如果您尝试访问不存在的端点,则会引发 HTTPException 并由 FastAPI 自动处理。

然后,我们检查它是否是 Exception 的实例,它是 Python 的 in-built 异常 classes 之一。这涵盖了 ZeroDivisionErrorFileNotFoundError 等异常。这通常意味着这是我们代码的问题,例如试图打开一个不存在的文件、除以零、使用未知数属性,或引发未在端点函数内部处理的异常的其他内容。

else块无论如何都不应该触发的,可以去掉,只是为了安抚自己的良心。

设置status_codedetail、headers后,

    return templates.TemplateResponse(
        "404.html",
        {"request": request, "status_code": status_code, "detail": detail},
        status_code=status_code,
        headers=headers,
    )

我们 return 我们的 404 模板,TemplateResponse 函数接受一些参数,"404.html" 是我们想要 return 的文件,{"request": request, "status_code": status_code, "detail": detail} 是请求 object 和我们要填充的嵌入值(嵌入是在 jinja2 和 Python 之间传递信息的一种方式)。然后我们定义响应的状态代码,以及它的 headers.

This 是我与错误处理程序一起使用的 404 html 模板。

exception_handlers = {num: lost_page for num in range(400, 599)}
app = FastAPI(exception_handlers=exception_handlers)

异常处理程序使用字典理解来创建状态代码字典,以及应该调用的函数,

exception_handlers = {400: lost_page, 401: lost_page, 402: lost_page, ...}

就是这样理解之后的样子,直到599。

FastAPI 允许我们将此字典作为 FastAPI class,

的参数传递
app = FastAPI(exception_handlers=exception_handlers)

这告诉 FastAPI 在端点函数 return 是特定状态代码时 运行 以下函数。

总而言之,上面的代码片段和 this 错误模板应该可以帮助您以一种漂亮、user-friendly 和干净的方式处理所有 FastAPI 错误。