Files

86 lines
2.4 KiB
Python
Raw Permalink Normal View History

"""rssKeeper - FastAPI 入口"""
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from starlette.middleware.cors import CORSMiddleware
from database import init_db, SessionLocal
from scheduler import init_feed_jobs, stop_scheduler
from routers import feeds, articles, dashboard, external_api
import config
@asynccontextmanager
async def lifespan(app: FastAPI):
"""应用生命周期管理"""
# 启动时:初始化数据库 + 注册定时任务
init_db()
db = SessionLocal()
try:
init_feed_jobs(db)
finally:
db.close()
yield
# 关闭时:停止调度器
stop_scheduler()
app = FastAPI(
title="rssKeeper",
description="RSS 抓取、管理与检索系统",
version="1.0.0",
lifespan=lifespan,
)
2026-06-11 14:31:29 +08:00
# CORS — 仅允许同源和开发环境
app.add_middleware(
CORSMiddleware,
2026-06-11 14:31:29 +08:00
allow_origins=[
"http://localhost:7329",
"http://localhost:7330",
"http://127.0.0.1:7329",
],
allow_credentials=False,
allow_methods=["GET", "POST", "PUT", "DELETE"],
allow_headers=["Content-Type", "Authorization", "X-API-Key"],
)
# API 路由
app.include_router(feeds.router, prefix=config.API_PREFIX)
app.include_router(articles.router, prefix=config.API_PREFIX)
app.include_router(dashboard.router, prefix=config.API_PREFIX)
app.include_router(external_api.router, prefix=config.EXTERNAL_API_PREFIX)
@app.get("/api/health")
def health_check():
"""健康检查"""
return {"status": "ok", "service": "rssKeeper"}
# 静态文件服务(前端构建产物)
static_dir = os.path.join(config.BASE_DIR, "static")
if os.path.exists(static_dir):
app.mount("/static", StaticFiles(directory=static_dir), name="static")
2026-06-11 14:31:29 +08:00
# API 路径白名单 — 这些路径不应被 SPA 兜底
_API_PATHS = {
"api", "docs", "openapi.json", "redoc",
}
@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
"""Vue SPA 路由回退"""
2026-06-11 14:31:29 +08:00
# API/文档路由不走 SPA 兜底
first_seg = full_path.split("/")[0] if full_path else ""
if first_seg in _API_PATHS:
return {"detail": "Not found"}
index_path = os.path.join(static_dir, "index.html")
if os.path.exists(index_path):
return FileResponse(index_path)
return {"detail": "Frontend not built"}