diff --git a/jyls_django/middleware.py b/jyls_django/middleware.py index d3d7e4a..ba132bf 100644 --- a/jyls_django/middleware.py +++ b/jyls_django/middleware.py @@ -235,8 +235,43 @@ class ApiLoggingMiddleware(MiddlewareMixin): 'EditBonusChange': '编辑变更', 'DeleteBonusChange': '删除变更', 'OperationLogView': '操作日志查询', + 'LawyersdocumentsDetail': '文件详情', # 确保映射正确 + 'BulletinDetail': '公告详情', # 确保映射正确 + 'ScheduleDetail': '日程详情', # 确保映射正确 + # 添加路径变体的映射 + 'Bulletindetail': '公告详情', # bulletindetail 路径 + 'Scheduledetail': '日程详情', # scheduledetail 路径 + 'Lawyersdocumentsdetail': '文件详情', # lawdisplay 路径对应的类 } - return name_mapping.get(class_name, None) + # 先尝试直接匹配 + result = name_mapping.get(class_name, None) + if result: + return result + + # 如果直接匹配失败,尝试不区分大小写匹配 + for key, value in name_mapping.items(): + if key.lower() == class_name.lower(): + return value + + return None + + def path_to_class_name(self, path): + """从URL路径推断可能的类名""" + # 移除前导斜杠并分割路径 + parts = path.strip('/').split('/') + if not parts or not parts[-1]: + return None + + # 获取最后一部分(通常是视图名称) + last_part = parts[-1] + + # 将下划线或连字符分隔的名称转换为驼峰命名 + # 例如: bulletindetail -> BulletinDetail + words = last_part.replace('-', '_').split('_') + class_name = ''.join(word.capitalize() for word in words) + + # 返回转换后的类名(即使不是标准驼峰命名也返回,让调用者尝试匹配) + return class_name if class_name else None def func_name_to_description(self, func_name): """从函数名转换为中文描述""" @@ -278,6 +313,7 @@ class ApiLoggingMiddleware(MiddlewareMixin): return response # 正常请求,记录详细日志 + description = None try: # 解析URL获取view函数 resolver_match = resolve(request.path) @@ -285,8 +321,6 @@ class ApiLoggingMiddleware(MiddlewareMixin): view_class = getattr(view_func, 'view_class', None) # 获取接口描述 - description = None - if view_class: # 优先从对应方法的docstring获取(针对APIView) method = request.method.lower() @@ -316,29 +350,46 @@ class ApiLoggingMiddleware(MiddlewareMixin): func_name = view_func.__name__ description = self.func_name_to_description(func_name) - # 如果还是没有找到描述,使用默认值 - if not description: - description = '未知接口' - - # 记录日志,格式与Django默认格式保持一致,并在最后添加接口描述 - timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') - log_message = f'{timestamp} "{request.method} {request.path} HTTP/1.1" {response.status_code} {description}' - - # 使用print输出到控制台(与Django开发服务器日志格式保持一致) - print(log_message) - except Resolver404: - # URL无法解析 - # 如果是未授权请求,可能是恶意扫描,只记录简要信息 - if is_unauthorized: - timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') - print(f'{timestamp} [未授权访问] "{request.method} {request.path}" {response.status_code}') - else: - timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') - print(f'{timestamp} "{request.method} {request.path} HTTP/1.1" {response.status_code} 未知接口') - except Exception: - # 发生异常时不影响请求处理,使用默认格式 - timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') - print(f'{timestamp} "{request.method} {request.path} HTTP/1.1" {response.status_code} 未知接口') + # URL无法解析,尝试从路径推断 + possible_class_name = self.path_to_class_name(request.path) + if possible_class_name: + description = self.class_name_to_description(possible_class_name) + # 如果直接匹配失败,尝试匹配常见的变体 + if not description and possible_class_name: + # 尝试匹配:Bulletindetail -> BulletinDetail + if possible_class_name.lower().endswith('detail'): + # 将 detail 前的部分首字母大写 + base = possible_class_name[:-6] # 移除 'detail' + if base: + # 尝试匹配:Bulletin + Detail + variant = base.capitalize() + 'Detail' + description = self.class_name_to_description(variant) + except Exception as e: + # 发生异常时,尝试从路径推断 + try: + possible_class_name = self.path_to_class_name(request.path) + if possible_class_name: + description = self.class_name_to_description(possible_class_name) + # 如果直接匹配失败,尝试匹配常见的变体 + if not description and possible_class_name: + if possible_class_name.lower().endswith('detail'): + base = possible_class_name[:-6] + if base: + variant = base.capitalize() + 'Detail' + description = self.class_name_to_description(variant) + except: + pass + + # 如果还是没有找到描述,使用默认值 + if not description: + description = '未知接口' + + # 记录日志,格式与Django默认格式保持一致,并在最后添加接口描述 + timestamp = datetime.now().strftime('[%d/%b/%Y %H:%M:%S]') + log_message = f'{timestamp} "{request.method} {request.path} HTTP/1.1" {response.status_code} {description}' + + # 使用print输出到控制台(与Django开发服务器日志格式保持一致) + print(log_message) return response