如何使用 FastAPI 返回自定义 404 Not Found 页面?
- 2025-01-17 09:23:00
- admin 原创
- 104
问题描述:
我正在为 Discord 制作一个 rick roll 网站,我想重定向到404
响应状态代码上的 rick roll 页面。
我尝试了以下操作,但没有效果:
@app.exception_handler(fastapi.HTTPException)
async def http_exception_handler(request, exc):
...
解决方案 1:
更新
更优雅的解决方案是使用自定义异常处理程序,传递您想要处理的异常的状态代码,如下所示:
from fastapi.responses import RedirectResponse
from fastapi.exceptions import HTTPException
@app.exception_handler(404)
async def not_found_exception_handler(request: Request, exc: HTTPException):
return RedirectResponse('https://fastapi.tiangolo.com')
或者,exception_handlers
像这样使用 FastAPI 类的参数:
async def not_found_error(request: Request, exc: HTTPException):
return RedirectResponse('https://fastapi.tiangolo.com')
exception_handlers = {404: not_found_error}
app = FastAPI(exception_handlers=exception_handlers)
注意:在上面的例子中,RedirectResponse
返回了 a,因为 OP 要求重定向用户。但是,您可以返回一些自定义的Response
或HTMLResponse
,Jinja2 TemplateResponse
如下例所示。
工作示例
应用程序
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from fastapi.exceptions import HTTPException
async def not_found_error(request: Request, exc: HTTPException):
return templates.TemplateResponse('404.html', {'request': request}, status_code=404)
async def internal_error(request: Request, exc: HTTPException):
return templates.TemplateResponse('500.html', {'request': request}, status_code=500)
templates = Jinja2Templates(directory='templates')
exception_handlers = {
404: not_found_error,
500: internal_error
}
app = FastAPI(exception_handlers=exception_handlers)
模板/404.html
<!DOCTYPE html>
<html>
<title>Not Found</title>
<body>
<h1>Not Found</h1>
<p>The requested resource was not found on this server.</p>
</body>
</html>
模板/500.html
<!DOCTYPE html>
<html>
<title>Internal Server Error</title>
<body>
<h1>Internal Server Error</h1>
<p>The server encountered an internal error or
misconfiguration and was unable to complete your request.
</p>
</body>
</html>
原始答案
您需要创建一个middleware
并检查的status_code
。response
如果是404
,则返回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
解决方案 2:
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
Details: {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)
这是我在几个项目中使用过的一段代码,它本质上是所有 400 和 500 状态代码的汇总。
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
# --- Constants --- #
templates = Jinja2Templates(directory="./templates")
此块导入相关库并初始化 Jinja2Templates,这使我们能够使用 FastAPI 呈现 HTML。文档。
让我们剖析一下
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
Details: {exception}"
return templates.TemplateResponse(
"404.html",
{"request": request, "status_code": status_code, "detail": detail},
status_code=status_code,
headers=headers,
)
FastAPI 的异常处理程序提供两个参数,导致异常的请求对象和引发的异常。
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-Name"] = exception.__class__.__name__
else:
status_code = 500
detail = f"Server Error
Details: {exception}"
如果exception
参数是 HTTPException(由 Starlette/FastAPI 引发),那么我们将适当地设置 status_code 和详细信息。HTTPException 的一个示例是 404 错误,如果您尝试访问不存在的端点,则会引发 HTTPException 并由 FastAPI 自动处理。
然后,我们检查它是否是 的一个实例Exception
,它是 Python 内置的异常类之一。这涵盖了诸如 、 等异常ZeroDivisionError
。FileNotFoundError
这通常意味着我们的代码存在问题,例如尝试打开不存在的文件、除以零、使用未知属性或其他引发了未在端点函数内部处理的异常的情况。
else
无论如何,这种阻止都不会被触发,并且可以被移除,这只是我为了安抚自己的良心而保留的东西。
status_code
设置、和 标头后detail
,
return templates.TemplateResponse(
"404.html",
{"request": request, "status_code": status_code, "detail": detail},
status_code=status_code,
headers=headers,
)
我们返回 404 模板,TemplateResponse 函数接受几个参数,"404.html"
即我们想要返回的文件、{"request": request, "status_code": status_code, "detail": detail}
请求对象和我们想要填充的嵌入值(嵌入是在 jinja2 和 Python 之间传递信息的一种方式)。然后我们定义响应的状态代码及其标头。
这是我与错误处理程序一起使用的 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
,
app = FastAPI(exception_handlers=exception_handlers)
这告诉 FastAPI 当端点函数返回特定状态代码时运行以下函数。
总而言之,上面的代码片段和这个错误模板应该可以帮助您以一种良好、用户友好和干净的方式处理所有 FastAPI 错误。
扫码咨询,免费领取项目管理大礼包!