You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
2.7 KiB

"""
请求中间件
"""
import time
import uuid
from typing import Callable
from fastapi import Request, Response
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.types import ASGIApp
from app.utils.log import get_enhanced_logger, LogLevel
logger = get_enhanced_logger(__name__, LogLevel.DEBUG)
class RequestMiddleware(BaseHTTPMiddleware):
"""请求中间件 - 生成请求ID和记录请求日志"""
def __init__(self, app: ASGIApp):
super().__init__(app)
async def dispatch(self, request: Request, call_next: Callable) -> Response:
# 生成请求ID
request_id = str(uuid.uuid4())
request.state.request_id = request_id
# 记录请求开始
start_time = time.time()
logger.info("请求开始",
request_id=request_id,
method=request.method,
url=str(request.url),
client_ip=request.client.host if request.client else "unknown",
user_agent=request.headers.get("user-agent", "unknown"))
try:
# 处理请求
response = await call_next(request)
# 计算处理时间
process_time = time.time() - start_time
# 记录请求完成
logger.info("请求完成",
request_id=request_id,
method=request.method,
url=str(request.url),
status_code=response.status_code,
process_time_ms=round(process_time * 1000, 2))
# 添加请求ID到响应头
response.headers["X-Request-ID"] = request_id
response.headers["X-Process-Time"] = str(round(process_time * 1000, 2))
return response
except Exception as e:
# 计算处理时间
process_time = time.time() - start_time
# 记录请求异常
logger.error("请求异常",
request_id=request_id,
method=request.method,
url=str(request.url),
exception=str(e),
process_time_ms=round(process_time * 1000, 2))
# 重新抛出异常,让异常处理器处理
raise
def add_middleware(app: ASGIApp) -> None:
"""添加中间件到应用"""
try:
# 添加请求中间件
app.add_middleware(RequestMiddleware)
logger.info("中间件添加成功")
except Exception as e:
logger.error("添加中间件失败", error=str(e))
raise