feat(system):优化后端

1.新增后端测试
2.增加了后端的加密
3.增加了i18n(国际化)
This commit is contained in:
2026-05-31 15:39:34 +00:00
parent affe460180
commit 99520c69d7
118 changed files with 8174 additions and 1491 deletions
+82 -49
View File
@@ -16,6 +16,7 @@ import os
from typing import Dict
from fastapi import FastAPI, WebSocket, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from ray import serve
@@ -23,26 +24,68 @@ from ray import serve
from .agent import agent_router
from .auth import auth_router
from .cluster import cluster_router
from .health import health_router
from .platform.frontend import client_router
from .platform.onebot import onebot_router
from .provider import provider_router
from .resource import resource_router
from .workflow import workflow_router
from .chat import chat_router
from kilostar.utils.error import (
DemandError,
ModelNotExistError,
UserError,
UserNotExistError,
UserPasswordError,
ProviderError,
ProviderNotExistError,
WorkflowError,
WorkflowExit,
KiloStarError,
BusinessError,
InfraError,
)
from kilostar.utils.logger import get_logger
from kilostar.utils.request_context import (
bind_request_id,
new_request_id,
reset_request_id,
)
from kilostar.utils.i18n import t
_api_logger = get_logger("api")
def _get_locale(request: Request) -> str | None:
"""从请求头解析首选语言,供异常 handler 使用。"""
return request.headers.get("accept-language") or None
app = FastAPI()
_cors_origins_env = os.environ.get("KILOSTAR_CORS_ORIGINS", "*")
_cors_origins = [o.strip() for o in _cors_origins_env.split(",") if o.strip()]
_allow_credentials = "*" not in _cors_origins
app.add_middleware(
CORSMiddleware,
allow_origins=_cors_origins,
allow_credentials=_allow_credentials,
allow_methods=["*"],
allow_headers=["*"],
)
@app.middleware("http")
async def request_id_middleware(request: Request, call_next):
"""请求级 ``request_id`` 注入。
入口策略:``X-Request-Id`` 头存在则继承(便于网关/前端串联调用链),
否则生成新的 UUID。退出时把它写到响应头,方便客户端日志对账。
contextvars 让同一请求生命周期内所有协程的日志都自动带上这个 ID。
"""
incoming = request.headers.get("X-Request-Id", "").strip()
request_id = incoming or new_request_id()
token = bind_request_id(request_id)
try:
response = await call_next(request)
finally:
reset_request_id(token)
response.headers["X-Request-Id"] = request_id
return response
app.include_router(health_router) # 健康检查
app.include_router(client_router) # 客户端路径
app.include_router(onebot_router) # OneBot v11 路径
app.include_router(auth_router) # 用户路径
app.include_router(provider_router) # 供应商路径
app.include_router(resource_router) # 资源路径
@@ -52,49 +95,39 @@ app.include_router(workflow_router) # workflow路径
app.include_router(chat_router) # chat路径
@app.exception_handler(UserNotExistError)
async def user_not_exist_handler(request: Request, exc: UserNotExistError):
return JSONResponse(status_code=404, content={"message": "用户不存在"})
@app.exception_handler(BusinessError)
async def business_error_handler(request: Request, exc: BusinessError):
"""业务可预期错误:按 ``http_status`` 返回 4xx,附 ``code`` + 异常消息。"""
return JSONResponse(
status_code=exc.http_status,
content={"code": exc.code, "message": str(exc) or exc.code},
)
@app.exception_handler(UserPasswordError)
async def user_password_handler(request: Request, exc: UserPasswordError):
return JSONResponse(status_code=401, content={"message": "密码错误"})
@app.exception_handler(InfraError)
async def infra_error_handler(request: Request, exc: InfraError):
"""系统失败错误:落日志后返回脱敏的 5xx。"""
_api_logger.exception(
f"InfraError on {request.method} {request.url.path}: {exc}"
)
loc = _get_locale(request)
return JSONResponse(
status_code=exc.http_status,
content={"code": exc.code, "message": t("internal_error", accept_language=loc)},
)
@app.exception_handler(UserError)
async def user_error_handler(request: Request, exc: UserError):
return JSONResponse(status_code=400, content={"message": "用户相关错误"})
@app.exception_handler(ProviderNotExistError)
async def provider_not_exist_handler(request: Request, exc: ProviderNotExistError):
return JSONResponse(status_code=404, content={"message": "服务提供商不存在"})
@app.exception_handler(ProviderError)
async def provider_error_handler(request: Request, exc: ProviderError):
return JSONResponse(status_code=400, content={"message": "服务提供商错误"})
@app.exception_handler(ModelNotExistError)
async def model_not_exist_handler(request: Request, exc: ModelNotExistError):
return JSONResponse(status_code=404, content={"message": "模型不存在"})
@app.exception_handler(DemandError)
async def demand_error_handler(request: Request, exc: DemandError):
return JSONResponse(status_code=400, content={"message": "需求格式错误或不满足"})
@app.exception_handler(WorkflowExit)
async def workflow_exit_handler(request: Request, exc: WorkflowExit):
return JSONResponse(status_code=400, content={"message": "工作流已退出"})
@app.exception_handler(WorkflowError)
async def workflow_error_handler(request: Request, exc: WorkflowError):
return JSONResponse(status_code=500, content={"message": "工作流执行错误"})
@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception):
"""全局兜底:未预期的异常落日志后返回脱敏的 500,避免泄露 traceback。"""
_api_logger.exception(
f"Unhandled exception on {request.method} {request.url.path}: {exc}"
)
loc = _get_locale(request)
return JSONResponse(
status_code=500,
content={"code": "internal_error", "message": t("internal_error", accept_language=loc)},
)
base_dir = os.path.dirname(
@@ -129,7 +162,7 @@ if os.path.exists(frontend_dir):
if os.path.exists(index_path):
return FileResponse(index_path)
return JSONResponse(
status_code=404, content={"detail": "Frontend build not found"}
status_code=404, content={"detail": t("frontend_not_found")}
)
else:
import logging