#!/usr/bin/env python3 # -*- coding: utf-8 -*- from contextlib import asynccontextmanager from fastapi import Depends, FastAPI from fastapi_limiter import FastAPILimiter from fastapi_pagination import add_pagination from starlette.middleware.authentication import AuthenticationMiddleware from backend.app.api.routers import v1 from backend.app.common.exception.exception_handler import register_exception from backend.app.common.redis import redis_client from backend.app.core.conf import settings from backend.app.database.db_mysql import create_table from backend.app.middleware.jwt_auth_middleware import JwtAuthMiddleware from backend.app.middleware.opera_log_middleware import OperaLogMiddleware from backend.app.utils.demo_site import demo_site from backend.app.utils.health_check import ensure_unique_route_names, http_limit_callback from backend.app.utils.openapi import simplify_operation_ids from backend.app.utils.serializers import MsgSpecJSONResponse @asynccontextmanager async def register_init(app: FastAPI): """ 启动初始化 :return: """ # 创建数据库表 await create_table() # 连接 redis await redis_client.open() # 初始化 limiter await FastAPILimiter.init(redis_client, prefix=settings.LIMITER_REDIS_PREFIX, http_callback=http_limit_callback) yield # 关闭 redis 连接 await redis_client.close() # 关闭 limiter await FastAPILimiter.close() def register_app(): # FastAPI app = FastAPI( title=settings.TITLE, version=settings.VERSION, description=settings.DESCRIPTION, docs_url=settings.DOCS_URL, redoc_url=settings.REDOCS_URL, openapi_url=settings.OPENAPI_URL, default_response_class=MsgSpecJSONResponse, lifespan=register_init, ) # 静态文件 register_static_file(app) # 中间件 register_middleware(app) # 路由 register_router(app) # 分页 register_page(app) # 全局异常处理 register_exception(app) return app def register_static_file(app: FastAPI): """ 静态文件交互开发模式, 生产使用 nginx 静态资源服务 :param app: :return: """ if settings.STATIC_FILES: import os from fastapi.staticfiles import StaticFiles if not os.path.exists('./static'): os.mkdir('./static') app.mount('/static', StaticFiles(directory='static'), name='static') def register_middleware(app: FastAPI): """ 中间件,执行顺序从下往上 :param app: :return: """ # Gzip: Always at the top if settings.MIDDLEWARE_GZIP: from fastapi.middleware.gzip import GZipMiddleware app.add_middleware(GZipMiddleware) # Opera log app.add_middleware(OperaLogMiddleware) # JWT auth, required app.add_middleware( AuthenticationMiddleware, backend=JwtAuthMiddleware(), on_error=JwtAuthMiddleware.auth_exception_handler ) # Access log if settings.MIDDLEWARE_ACCESS: from backend.app.middleware.access_middleware import AccessMiddleware app.add_middleware(AccessMiddleware) # CORS: Always at the end if settings.MIDDLEWARE_CORS: from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=['*'], allow_credentials=True, allow_methods=['*'], allow_headers=['*'], ) def register_router(app: FastAPI): """ 路由 :param app: FastAPI :return: """ dependencies = [Depends(demo_site)] if settings.DEMO_MODE else None # API app.include_router(v1, dependencies=dependencies) # Extra ensure_unique_route_names(app) simplify_operation_ids(app) def register_page(app: FastAPI): """ 分页查询 :param app: :return: """ add_pagination(app)