From 326bdf9a17594185e1d1fbbcd7643eef1b4eb2fc Mon Sep 17 00:00:00 2001 From: shj366 <73154524+shj366@users.noreply.github.com> Date: Sat, 10 Jan 2026 18:23:02 +0800 Subject: [PATCH] Fix opera log non-json data overload (#998) * fix: skip non-json body logging for multipart uploads * Update truncation implementation --- backend/middleware/opera_log_middleware.py | 52 +++++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/backend/middleware/opera_log_middleware.py b/backend/middleware/opera_log_middleware.py index 874cce67..936718a9 100644 --- a/backend/middleware/opera_log_middleware.py +++ b/backend/middleware/opera_log_middleware.py @@ -1,3 +1,4 @@ +import json import time from asyncio import Queue @@ -150,7 +151,7 @@ class OperaLogMiddleware(BaseHTTPMiddleware): return response - async def get_request_args(self, request: Request) -> dict[str, Any] | None: + async def get_request_args(self, request: Request) -> dict[str, Any] | None: # noqa: C901 """ 获取请求参数 @@ -178,26 +179,65 @@ class OperaLogMiddleware(BaseHTTPMiddleware): if body_data: # 注意:非 json 数据默认使用 data 作为键 if 'application/json' not in content_type: - args['data'] = str(body_data) + args['data'] = body_data.decode('utf-8', 'ignore') if isinstance(body_data, bytes) else str(body_data) else: json_data = await request.json() if isinstance(json_data, dict): args['json'] = await self.desensitization(json_data) else: - args['data'] = str(body_data) + args['data'] = str(json_data) # 表单参数 form_data = await request.form() if len(form_data) > 0: + serialized_form = {} for k, v in form_data.items(): - form_data = {k: v.filename} if isinstance(v, UploadFile) else {k: v} + if isinstance(v, UploadFile): + serialized_form[k] = { + 'filename': v.filename, + 'content_type': v.content_type, + 'size': v.size, + } + else: + serialized_form[k] = v if 'multipart/form-data' not in content_type: - args['x-www-form-urlencoded'] = await self.desensitization(form_data) + args['x-www-form-urlencoded'] = await self.desensitization(serialized_form) else: - args['form-data'] = await self.desensitization(form_data) + args['form-data'] = await self.desensitization(serialized_form) + + if args: + args = self.truncate(args) return args or None + @staticmethod + def truncate(args: dict[str, Any]) -> dict[str, Any]: + """ + 截断处理 + + :param args: 需要截断的请求参数字典 + :return: + """ + max_size = 10240 # 数据最大大小(字节) + + try: + args_str = json.dumps(args, ensure_ascii=False) + args_size = len(args_str.encode('utf-8')) + + if args_size > max_size: + truncated_str = args_str[:max_size] + return { + '_truncated': True, + '_original_size': args_size, + '_max_size': max_size, + '_message': f'数据过大已截断:原始大小 {args_size} 字节,限制 {max_size} 字节', + 'data_preview': truncated_str, + } + except Exception as e: + log.error(f'请求参数截断处理失败:{e}') + + return args + @staticmethod @sync_to_async def desensitization(args: dict[str, Any]) -> dict[str, Any]: