83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
from fastapi import FastAPI
|
||
from fastapi.responses import FileResponse
|
||
from fastapi import Request
|
||
from contextlib import asynccontextmanager
|
||
from slowapi import Limiter, _rate_limit_exceeded_handler
|
||
from slowapi.util import get_remote_address
|
||
from slowapi.errors import RateLimitExceeded
|
||
|
||
from pkg.utils import raise_internal_error
|
||
from routes import (session, admin, object, ota)
|
||
from model.database import Database
|
||
import os
|
||
import pkg.conf
|
||
from pkg import utils
|
||
|
||
from loguru import logger
|
||
|
||
Router = [admin, session, object, ota]
|
||
|
||
# Findreve 的生命周期
|
||
@asynccontextmanager
|
||
async def lifespan(app: FastAPI):
|
||
await Database().init_db()
|
||
yield
|
||
|
||
# 定义 Findreve 服务器
|
||
app = FastAPI(
|
||
title=pkg.conf.APP_NAME,
|
||
version=pkg.conf.VERSION,
|
||
summary=pkg.conf.summary,
|
||
description=pkg.conf.description,
|
||
lifespan=lifespan
|
||
)
|
||
|
||
@app.exception_handler(Exception)
|
||
async def handle_unexpected_exceptions(request: Request, exc: Exception):
|
||
"""
|
||
捕获所有未经处理的异常,防止敏感信息泄露。
|
||
"""
|
||
# 1. 为开发人员记录详细的、包含完整堆栈跟踪的错误日志
|
||
logger.exception(
|
||
f"An unhandled exception occurred for request: {request.method} {request.url.path}"
|
||
)
|
||
|
||
raise_internal_error()
|
||
|
||
|
||
# 挂载后端路由
|
||
for router in Router:
|
||
app.include_router(router.Router)
|
||
|
||
# 挂载Slowapi限流中间件
|
||
limiter = Limiter(key_func=get_remote_address)
|
||
app.state.limiter = limiter
|
||
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
|
||
|
||
@app.get("/")
|
||
async def frontend_index():
|
||
if not os.path.exists("dist/index.html"):
|
||
utils.raise_not_found("Index not found")
|
||
return FileResponse("dist/index.html")
|
||
|
||
# 回退路由
|
||
@app.get("/{path:path}")
|
||
async def frontend_path(path: str):
|
||
if not os.path.exists("dist/index.html"):
|
||
utils.raise_not_found("Index not found, please build frontend first.")
|
||
|
||
# 排除API路由
|
||
if path.startswith("api/"):
|
||
utils.raise_not_found("API route not found")
|
||
|
||
# 检查是否是静态资源请求
|
||
if path.startswith("assets/") and os.path.exists(f"dist/{path}"):
|
||
return FileResponse(f"dist/{path}")
|
||
|
||
# 检查文件是否存在于dist目录
|
||
dist_file_path = os.path.join("dist", path)
|
||
if os.path.exists(dist_file_path) and not os.path.isdir(dist_file_path):
|
||
return FileResponse(dist_file_path)
|
||
|
||
# 对于所有其他前端路由,返回index.html让Vue Router处理
|
||
return FileResponse("dist/index.html") |