main.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. """FastAPI 应用入口"""
  2. from contextlib import asynccontextmanager
  3. import logging
  4. from fastapi import FastAPI
  5. from fastapi.middleware.cors import CORSMiddleware
  6. from app.core.config import settings
  7. from app.core.database import engine, SessionLocal
  8. from app.core.api_request_log_middleware import ApiRequestLogMiddleware
  9. from app.core.api_crypto_middleware import ApiCryptoMiddleware
  10. from app.models import models # noqa: F401
  11. from app.api import (
  12. public_router,
  13. admin_router,
  14. deliver_router,
  15. mini_client_router,
  16. mini_client_extra_router,
  17. mini_common_router,
  18. mini_message_router,
  19. mini_supplier_router,
  20. delivery_router,
  21. mini_deliverer_router,
  22. upload_router,
  23. order_adjust_router,
  24. payment_router,
  25. attachment_router,
  26. invoice_router,
  27. system_config_router,
  28. delivery_warning_router,
  29. message_router,
  30. menu_router,
  31. system_router,
  32. product_banner_router,
  33. product_detail_media_router,
  34. product_parameter_router,
  35. category_parameter_router,
  36. product_parameter_value_router,
  37. product_review_router,
  38. mini_review_router,
  39. )
  40. @asynccontextmanager
  41. async def lifespan(app: FastAPI):
  42. """应用生命周期管理"""
  43. # 启动时执行
  44. from app.core import login_crypto
  45. login_crypto.ensure_initialized()
  46. from app.tasks import init_scheduled_tasks
  47. try:
  48. init_scheduled_tasks(SessionLocal)
  49. except Exception as e:
  50. import logging
  51. logging.warning(f"定时任务调度器启动失败: {e}")
  52. yield
  53. # 关闭时执行
  54. from app.tasks import shutdown_scheduler
  55. try:
  56. shutdown_scheduler()
  57. except Exception:
  58. pass
  59. app = FastAPI(
  60. title=settings.APP_NAME,
  61. description="陇耘鲜达平台后端API",
  62. version="1.0.0",
  63. docs_url="/docs",
  64. redoc_url="/redoc",
  65. lifespan=lifespan
  66. )
  67. # CORS 跨域配置
  68. app.add_middleware(
  69. CORSMiddleware,
  70. allow_origins=settings.BACKEND_CORS_ORIGINS,
  71. allow_credentials=True,
  72. allow_methods=["*"],
  73. allow_headers=["*"],
  74. )
  75. app.add_middleware(ApiRequestLogMiddleware)
  76. app.add_middleware(ApiCryptoMiddleware)
  77. # 注册路由
  78. app.include_router(public_router, prefix=settings.API_V1_PREFIX)
  79. app.include_router(admin_router, prefix=settings.API_V1_PREFIX)
  80. app.include_router(deliver_router, prefix=settings.API_V1_PREFIX)
  81. app.include_router(mini_client_router)
  82. app.include_router(mini_supplier_router)
  83. app.include_router(delivery_router, prefix=settings.API_V1_PREFIX)
  84. app.include_router(mini_deliverer_router)
  85. app.include_router(mini_client_extra_router)
  86. app.include_router(mini_common_router)
  87. app.include_router(mini_message_router)
  88. app.include_router(upload_router)
  89. app.include_router(order_adjust_router)
  90. app.include_router(payment_router)
  91. app.include_router(attachment_router)
  92. app.include_router(invoice_router)
  93. app.include_router(system_config_router)
  94. app.include_router(delivery_warning_router)
  95. app.include_router(message_router)
  96. app.include_router(menu_router, prefix=settings.API_V1_PREFIX)
  97. app.include_router(system_router, prefix=settings.API_V1_PREFIX)
  98. app.include_router(product_banner_router, prefix=settings.API_V1_PREFIX)
  99. app.include_router(product_detail_media_router, prefix=settings.API_V1_PREFIX)
  100. app.include_router(product_parameter_router, prefix=settings.API_V1_PREFIX)
  101. app.include_router(category_parameter_router, prefix=settings.API_V1_PREFIX)
  102. app.include_router(product_parameter_value_router, prefix=settings.API_V1_PREFIX)
  103. app.include_router(product_review_router, prefix=settings.API_V1_PREFIX)
  104. app.include_router(mini_review_router)
  105. from app.ws.price_updates import register_ws_routes
  106. register_ws_routes(app)
  107. logger = logging.getLogger("sqxp")
  108. def _mask_secret(value: str) -> str:
  109. if not value:
  110. return "(empty)"
  111. if len(value) <= 6:
  112. return "*" * len(value)
  113. return f"{value[:3]}***{value[-3:]}"
  114. _api_crypto_boot_msg = (
  115. "API_CRYPTO_BOOT "
  116. f"enabled={settings.API_ENCRYPT_ENABLED} "
  117. f"fail_open={settings.API_ENCRYPT_FAIL_OPEN} "
  118. f"fixed_secret={_mask_secret(settings.API_ENCRYPT_FIXED_SECRET)} "
  119. f"ts_skew_sec={settings.API_ENCRYPT_TS_SKEW_SEC} "
  120. f"nonce_ttl_sec={settings.API_ENCRYPT_NONCE_TTL_SEC} "
  121. f"exclude_count={len([x for x in (settings.API_ENCRYPT_EXCLUDE_PATHS or '').split(',') if x.strip()])}"
  122. )
  123. print(_api_crypto_boot_msg)
  124. logger.info(_api_crypto_boot_msg)
  125. @app.get("/")
  126. def root():
  127. """根路径"""
  128. return {
  129. "name": settings.APP_NAME,
  130. "version": "1.0.0",
  131. "docs": "/docs"
  132. }
  133. @app.get("/health")
  134. def health_check():
  135. """健康检查"""
  136. return {"status": "healthy"}