From 9784f5f436fd1ea49eb502dc77e191c8549ca72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E8=88=AA=E5=AE=87?= <3364451258@qq.com> Date: Sat, 11 Jul 2026 19:47:14 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20API=20=E5=AE=89=E5=85=A8=E5=8A=A0?= =?UTF-8?q?=E5=9B=BA=20=E2=80=94=20=E8=AF=B7=E6=B1=82=E4=BD=93=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E9=99=90=E5=88=B6=E3=80=81=E5=AE=A1=E8=AE=A1=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E3=80=81=E5=81=A5=E5=BA=B7=E6=A3=80=E6=9F=A5=E5=85=8D?= =?UTF-8?q?=E9=99=90=E9=80=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/server/app.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/server/app.py b/src/server/app.py index 3b0b96f..df909c6 100644 --- a/src/server/app.py +++ b/src/server/app.py @@ -1,5 +1,6 @@ """FastAPI 服务层.""" import os +import time import uuid import logging from pathlib import Path @@ -84,8 +85,36 @@ async def security_headers_middleware(request: Request, call_next): return response +@app.middleware("http") +async def body_size_limit_middleware(request: Request, call_next): + """限制请求体大小(防止内存耗尽攻击).""" + content_length = request.headers.get("content-length") + max_size = int(os.environ.get("MAX_REQUEST_BODY_SIZE", str(10 * 1024 * 1024))) # 默认 10MB + if content_length and int(content_length) > max_size: + raise HTTPException(status_code=413, detail="请求体过大") + return await call_next(request) + + +@app.middleware("http") +async def audit_log_middleware(request: Request, call_next): + """记录所有 API 请求的审计日志.""" + start = time.time() + response = await call_next(request) + duration_ms = (time.time() - start) * 1000 + logger.info( + "audit: %s %s → %d (%.1fms) [%s]", + request.method, request.url.path, + response.status_code, duration_ms, + request.client.host if request.client else "unknown", + ) + return response + + @app.middleware("http") async def rate_limit_middleware(request: Request, call_next): + # 健康检查和根路径不需要速率限制 + if request.url.path in ("/api/v1/health", "/"): + return await call_next(request) await rate_limiter(request) response = await call_next(request) return response