|
@@ -31,6 +31,7 @@ class LoggingMiddleware(BaseHTTPMiddleware):
|
|
|
start_time = time.perf_counter()
|
|
|
|
|
|
# 打印请求信息
|
|
|
+ request_id = TraceUtil.get_req_id()
|
|
|
logger.info(f"--> {request.method} {request.url.path} {request.client.host}")
|
|
|
if request.query_params:
|
|
|
logger.info(f"--> Query Params: {request.query_params}")
|
|
@@ -40,7 +41,7 @@ class LoggingMiddleware(BaseHTTPMiddleware):
|
|
|
try:
|
|
|
# starlette 中间件中不能读取请求数据,否则会进入循环等待 需要特殊处理或者换APIRoute实现
|
|
|
body = await request.json()
|
|
|
- logger.info(f"--> Body: {body}")
|
|
|
+ logger.info(f"--> Request Body: {body}")
|
|
|
except Exception as e:
|
|
|
logger.warning(f"Failed to parse JSON body: {e}")
|
|
|
|
|
@@ -50,7 +51,53 @@ class LoggingMiddleware(BaseHTTPMiddleware):
|
|
|
# 计算响应时间
|
|
|
process_time = time.perf_counter() - start_time
|
|
|
response.headers["X-Response-Time"] = f"{process_time:.2f}s"
|
|
|
- logger.info(f"<-- {response.status_code} {request.url.path} (took: {process_time:.2f}s)\n")
|
|
|
+
|
|
|
+ # 记录响应基本信息
|
|
|
+ logger.info(f"<-- Response: [Status: {response.status_code}, Type: {response.__class__.__name__}, Headers: {dict(response.headers)}]")
|
|
|
+
|
|
|
+ # 尝试记录响应体
|
|
|
+ try:
|
|
|
+ from starlette.responses import StreamingResponse, JSONResponse, Response
|
|
|
+ import json
|
|
|
+
|
|
|
+ # 针对不同类型的响应采用不同的解析方式
|
|
|
+ if isinstance(response, StreamingResponse):
|
|
|
+ logger.info("<-- Streaming response body (skipped logging)")
|
|
|
+ return response
|
|
|
+
|
|
|
+ # 获取响应体内容
|
|
|
+ body = None
|
|
|
+ if isinstance(response, JSONResponse):
|
|
|
+ body = response.body
|
|
|
+ elif hasattr(response, 'body'):
|
|
|
+ try:
|
|
|
+ body = await response.body()
|
|
|
+ except Exception as e:
|
|
|
+ logger.warning(f"<-- Failed to get response body: {e.__class__.__name__}: {str(e)}")
|
|
|
+ return response
|
|
|
+
|
|
|
+ # 解析并记录响应体
|
|
|
+ if body:
|
|
|
+ try:
|
|
|
+ if isinstance(body, bytes):
|
|
|
+ body = body.decode('utf-8')
|
|
|
+ if isinstance(body, str):
|
|
|
+ # 尝试解析为JSON
|
|
|
+ try:
|
|
|
+ body_json = json.loads(body)
|
|
|
+ logger.info(f"<-- Response Body (JSON): {body_json}")
|
|
|
+ except json.JSONDecodeError:
|
|
|
+ # 如果不是JSON格式,直接记录字符串内容
|
|
|
+ logger.info(f"<-- Response Body (Text): {body}")
|
|
|
+ except UnicodeDecodeError as e:
|
|
|
+ logger.warning(f"<-- Failed to decode response body: {str(e)}")
|
|
|
+ except Exception as e:
|
|
|
+ logger.warning(f"<-- Failed to process response body: {e.__class__.__name__}: {str(e)}")
|
|
|
+ except Exception as e:
|
|
|
+ logger.warning(f"<-- Failed to handle response body: {e.__class__.__name__}: {str(e)}")
|
|
|
+
|
|
|
+
|
|
|
+ logger.info(f"<-- {response.status_code} {request.url.path} (took: {process_time:.2f}s)")
|
|
|
|
|
|
return response
|
|
|
|
|
@@ -74,7 +121,7 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
status_code=status.HTTP_401_UNAUTHORIZED
|
|
|
)
|
|
|
|
|
|
- async def verify_token(authorization: str) -> Optional[dict]:
|
|
|
+ async def verify_token(self, authorization: str) -> Optional[dict]:
|
|
|
"""
|
|
|
验证 token 有效性
|
|
|
返回:验证成功返回用户信息字典,失败返回 None
|
|
@@ -93,7 +140,7 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
return {"id": 2, "username": "user", "role": "user"}
|
|
|
return None
|
|
|
|
|
|
- def should_intercept(path: str) -> bool:
|
|
|
+ def should_intercept(self, path: str) -> bool:
|
|
|
"""
|
|
|
判断是否需要拦截当前路径
|
|
|
"""
|
|
@@ -111,6 +158,12 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
return False
|
|
|
|
|
|
async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response:
|
|
|
+ # 初始化请求上下文
|
|
|
+ request.state.context = {
|
|
|
+ "request_id": TraceUtil.get_req_id(),
|
|
|
+ "client_ip": request.client.host
|
|
|
+ }
|
|
|
+
|
|
|
path = request.url.path
|
|
|
|
|
|
if not self.should_intercept(path):
|
|
@@ -128,16 +181,10 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
# 初始化操作:将用户信息添加到请求状态中
|
|
|
request.state.user = user_info
|
|
|
|
|
|
- # 添加请求上下文(示例)
|
|
|
- request.state.context = {
|
|
|
- "request_id": TraceUtil.set_req_id(request.headers.get("X-Request-ID")),
|
|
|
- "client_ip": request.client.host
|
|
|
- }
|
|
|
-
|
|
|
# 继续处理请求
|
|
|
response = await call_next(request)
|
|
|
# 可以在返回前添加统一响应处理(如添加头信息)
|
|
|
- response.headers["request-id"] = request.state.context["request_id"]
|
|
|
+ # response.headers["request-id"] = request.state.context["request_id"]
|
|
|
|
|
|
return response
|
|
|
|
|
@@ -146,7 +193,8 @@ class AuthMiddleware(BaseHTTPMiddleware):
|
|
|
def register_middlewares():
|
|
|
"""注册中间件(逆序执行)"""
|
|
|
return [
|
|
|
- # Middleware(LoggingMiddleware),
|
|
|
+ Middleware(TraceReqMiddleware), # 最先设置request_id
|
|
|
+ Middleware(LoggingMiddleware),
|
|
|
Middleware(
|
|
|
CORSMiddleware,
|
|
|
allow_origins=["*"],
|
|
@@ -154,6 +202,5 @@ def register_middlewares():
|
|
|
allow_methods=["*"],
|
|
|
allow_headers=["*"],
|
|
|
),
|
|
|
- Middleware(TraceReqMiddleware),
|
|
|
Middleware(AuthMiddleware),
|
|
|
]
|