【Dv3Admin】工具中间件配置文件解析

后台管理系统对接口调用监控和运行状态检测有严格要求,自定义中间件成为核心支撑组件。日志记录与健康检查机制,直接决定了系统问题追踪效率和服务稳定性。

解析 dvadmin/utils/middleware.py 中两个中间件的实现细节,剖析 API 日志自动收集与存活性探针设计,结合实际业务场景,探讨其在系统可靠性与可维护性方面的支撑作用。

文章目录

  • middleware.py
  • 项目源码解析
  • 应用案例
  • 总结

middleware.py

系统基于 Django 框架开发,提供企业级后台管理功能。dvadmin/utils/middleware.py 包含两个自定义中间件组件,一个用于记录 API 请求日志,一个用于健康检查。日志中间件自动捕获接口请求数据并写入日志表,健康检查中间件提供 /healthz/readiness 接口供监控系统探测服务与数据库、缓存可用性,增强系统的可观测性和稳定性。

项目特点 描述
技术栈 Django 中间件机制
功能定位 API访问日志记录与应用健康检查
日志收集 自动记录请求数据、响应状态、设备信息
健康探测 监控数据库和缓存服务连通性

dvadmin/utils/middleware.py 文件定义了两个中间件:ApiLoggingMiddlewareHealthCheckMiddlewareApiLoggingMiddleware 在接口请求完成后自动收集请求参数、IP地址、操作系统、浏览器类型、接口响应结果,并将这些信息存储到 OperationLog 表中。HealthCheckMiddleware 提供 /healthz/readiness 检测接口,分别检查应用存活状态以及数据库、缓存的连接状态,用于外部监控系统快速检测服务健康。

模块职责 说明
API 请求日志记录 捕获并存储接口访问相关信息,包括请求参数和响应结果
请求体敏感信息保护 自动屏蔽敏感字段如 password,防止泄露
接口访问模块识别 根据接口路径自动识别操作模块名称,辅助日志归类
应用存活性检测 提供 /healthz 接口,返回应用运行状态
系统依赖可用性检测 提供 /readiness 接口,检测数据库和缓存是否正常连接

在企业后台系统或对高可用性要求较高的服务中,dvadmin/utils/middleware.py 模块的日志记录与健康检查功能尤为重要。开发过程中能快速定位接口调用异常,生产环境中能够通过监控系统及时发现并处理数据库、缓存等依赖故障,减少服务不可用时间,提高系统稳定性和运维效率。

使用场景 说明
接口访问日志自动收集 每次接口调用自动记录请求和响应内容,方便后续问题排查
登录接口敏感信息保护 登录接口传递密码时自动脱敏,保障用户数据安全
应用存活性监控 Kubernetes 等平台通过 /healthz 监控应用是否挂掉
数据库连接状态监控 通过 /readiness 实时探测数据库连通性
缓存服务连接状态监控 实时检测 Memcached 等缓存服务是否可用

项目源码解析

API访问日志中间件

用于在系统运行时记录所有指定接口的请求与响应信息。通过拦截请求与响应,提取关键信息并保存到 OperationLog 表中,实现完整的操作审计。中间件与系统日志模型、请求工具函数、系统配置项如 API_LOG_ENABLEAPI_MODEL_MAP 紧密关联,具备很好的可控性和扩展性。

class ApiLoggingMiddleware(MiddlewareMixin):
    def __init__(self, get_response=None):
        super().__init__(get_response)
        self.enable = getattr(settings, 'API_LOG_ENABLE', None) or False
        self.methods = getattr(settings, 'API_LOG_METHODS', None) or set()
        self.operation_log_id = None

在请求进入视图处理之前,提取请求IP、请求参数、访问路径等基础信息,挂载到 request 对象上,供后续日志或权限控制模块使用。依赖 get_request_ipget_request_dataget_request_path 工具函数。

    @classmethod
    def __handle_request(cls, request):
        request.request_ip = get_request_ip(request)
        request.request_data = get_request_data(request)
        request.request_path = get_request_path(request)

在请求处理完成后,提取响应内容及请求关键信息,标准化格式后写入操作日志表 OperationLog,并动态补充模块名信息。对敏感字段如密码进行脱敏处理,确保日志记录的安全性。

    def __handle_response(self, request, response):
        if request.request_data.get('log_id', None) is None:
            return
        log_id = request.request_data.pop('log_id')
        body = getattr(request, 'request_data', {})
        if isinstance(body, dict) and body.get('password', ''):
            body['password'] = '*' * len(body['password'])
        if not hasattr(response, 'data') or not isinstance(response.data, dict):
            response.data = {}
        try:
            if not response.data and response.content:
                content = json.loads(response.content.decode())
                response.data = content if isinstance(content, dict) else {}
        except Exception:
            return
        user = get_request_user(request)
        info = {
            'request_ip': getattr(request, 'request_ip', 'unknown'),
            'creator': user if not isinstance(user, AnonymousUser) else None,
            'dept_belong_id': getattr(request.user, 'dept_id', None),
            'request_method': request.method,
            'request_path': request.request_path,
            'request_body': body,
            'response_code': response.data.get('code'),
            'request_os': get_os(request),
            'request_browser': get_browser(request),
            'request_msg': request.session.get('request_msg'),
            'status': True if response.data.get('code') in [2000, ] else False,
            'json_result': {"code": response.data.get('code'), "msg": response.data.get('msg')},
        }
        operation_log, creat = OperationLog.objects.update_or_create(defaults=info, id=log_id)
        if not operation_log.request_modular and settings.API_MODEL_MAP.get(request.request_path, None):
            operation_log.request_modular = settings.API_MODEL_MAP[request.request_path]
            operation_log.save()

在进入视图方法前,如果视图类绑定了 queryset,并且开启了接口日志记录,则预生成一条空白日志记录并保存log_id,方便后续补充详细内容。

    def process_view(self, request, view_func, view_args, view_kwargs):
        if hasattr(view_func, 'cls') and hasattr(view_func.cls, 'queryset'):
            if self.enable:
                if self.methods == 'ALL' or request.method in self.methods:
                    log = OperationLog(request_modular=get_verbose_name(view_func.cls.queryset))
                    log.save()
                    request.request_data['log_id'] = log.id

统一调用私有方法 __handle_request,确保所有请求信息在最早阶段被捕获处理,为后续中间件和视图处理做好准备。

    def process_request(self, request):
        self.__handle_request(request)

统一调用私有方法 __handle_response,在响应阶段补充日志信息并保存,保证数据的完整性和准确性。

    def process_response(self, request, response):
        if self.enable:
            if self.methods == 'ALL' or request.method in self.methods:
                self.__handle_response(request, response)
        return response

存活检查中间件

提供 /readiness/healthz 两个GET接口,分别用于检测数据库、缓存等依赖服务是否正常连接,以及服务器是否存活。适用于容器部署环境下的健康探针机制,增强系统可观测性。

class HealthCheckMiddleware(object):
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        if request.method == "GET":
            if request.path == "/readiness":
                return self.readiness(request)
            elif request.path == "/healthz":
                return self.healthz(request)
        return self.get_response(request)

直接返回 "OK" 字符串,表示服务器存活状态正常,不检查后端资源,适用于轻量级存活探针。

    def healthz(self, request):
        return HttpResponse("OK")

检测所有数据库连接和缓存连接是否正常,确保系统可以对外提供完整服务。出错时返回详细错误信息,便于快速定位故障点。

    def readiness(self, request):
        try:
            from django.db import connections
            for name in connections:
                cursor = connections[name].cursor()
                cursor.execute("SELECT 1;")
                row = cursor.fetchone()
                if row is None:
                    return HttpResponseServerError("db: invalid response")
        except Exception as e:
            logger.exception(e)
            return HttpResponseServerError("db: cannot connect to database.")

        try:
            from django.core.cache import caches
            from django.core.cache.backends.memcached import BaseMemcachedCache
            for cache in caches.all():
                if isinstance(cache, BaseMemcachedCache):
                    stats = cache._cache.get_stats()
                    if len(stats) != len(cache._servers):
                        return HttpResponseServerError("cache: cannot connect to cache.")
        except Exception as e:
            logger.exception(e)
            return HttpResponseServerError("cache: cannot connect to cache.")

        return HttpResponse("OK")

应用案例

中间件在后台系统日志监控与健康检查中的实际应用

在后台管理系统中,接口调用的日志记录与应用存活性监控是保证系统稳定运行的重要手段。通过 dvadmin/utils/middleware.py 模块,系统实现了两个自定义中间件:ApiLoggingMiddleware 用于自动记录 API 请求日志,HealthCheckMiddleware 提供存活性与依赖健康检查接口。

功能点 内容描述
场景需求 提供接口调用日志记录与应用存活性监控能力,确保系统的可观测性与稳定性,支持高并发与分布式部署场景下的快速诊断与问题追踪。
核心模块 dvadmin/utils/middleware.py:包含两个自定义中间件:ApiLoggingMiddlewareHealthCheckMiddleware
支持功能 - API 请求日志记录:通过 ApiLoggingMiddleware,自动记录所有 API 请求的详细日志,包括请求时间、参数和响应。
- 健康检查接口:通过 HealthCheckMiddleware 提供存活性检查与依赖健康检查,快速判断系统是否正常运行。
实现机制 - 基于 Django 中间件:拦截所有 HTTP 请求和响应,提取相关信息进行日志记录与健康检查。
- 日志记录:记录请求路径、方法、参数、响应状态码以及耗时等,便于问题定位与性能分析。
- 健康检查:实现轻量级存活性检查接口(如 /health),检查服务状态与依赖资源(如数据库、缓存)的可用性。

这两者共同支撑了系统的可观测性与稳定性,尤其在高并发和大规模分布式部署的场景中,能够高效追踪问题并进行快速故障诊断。

功能点 内容描述
应用场景 - 接口调用追踪:记录所有 API 调用日志,用于问题排查与性能优化。
- 存活性监控:通过 /health 接口监控应用的运行状态,便于运维自动化与报警通知。
- 依赖检查:在健康检查接口中扩展数据库、缓存等依赖服务的状态检查,确保系统运行的完整性。
优势 - 提升系统的可观测性,便于快速诊断问题。
- 支持高并发场景下的稳定运行与问题追踪。
- 确保分布式部署的健康状态可控。
扩展能力 - 支持更多日志存储方式,如日志聚合与分布式追踪。
- 健康检查接口可扩展更多依赖服务的检测能力,如消息队列与外部 API。

API 请求日志记录中间件

在每次 API 请求时,ApiLoggingMiddleware 中间件会捕获请求的基本信息(如请求 IP、请求参数、请求路径、操作系统、浏览器类型等),并在响应阶段记录下请求结果及响应状态。所有的日志数据会被存储到 OperationLog 表中,确保系统操作记录的完整性与追溯能力。日志信息会在每个请求周期内动态生成,并可根据需求进行过滤与脱敏处理。

class ApiLoggingMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.request_ip = get_request_ip(request)
        request.request_data = get_request_data(request)
        request.request_path = get_request_path(request)

    def process_response(self, request, response):
        log_id = request.request_data.get('log_id', None)
        if log_id:
            body = getattr(request, 'request_data', {})
            if body.get('password'):
                body['password'] = '*' * len(body['password'])
            info = {
                'request_ip': request.request_ip,
                'request_method': request.method,
                'request_path': request.request_path,
                'response_code': response.data.get('code'),
                'request_os': get_os(request),
                'status': True if response.data.get('code') == 2000 else False,
            }
            operation_log, _ = OperationLog.objects.update_or_create(defaults=info, id=log_id)

应用存活性与依赖服务探测

为了确保服务的高可用性,HealthCheckMiddleware 提供了 /healthz/readiness 两个接口,分别用于监控应用存活状态和依赖服务(如数据库、缓存等)的可用性。/healthz 接口仅检测服务器的存活情况,/readiness 接口则进一步检查数据库和缓存服务的连接状态,确保系统能够处理来自外部的正常请求。

class HealthCheckMiddleware(object):
    def __call__(self, request):
        if request.path == "/healthz":
            return self.healthz(request)
        elif request.path == "/readiness":
            return self.readiness(request)
        return self.get_response(request)

    def healthz(self, request):
        return HttpResponse("OK")

    def readiness(self, request):
        try:
            from django.db import connections
            cursor = connections['default'].cursor()
            cursor.execute("SELECT 1;")
            row = cursor.fetchone()
            if row is None:
                return HttpResponseServerError("db: invalid response")
        except Exception as e:
            logger.exception(e)
            return HttpResponseServerError("db: cannot connect to database.")
        return HttpResponse("OK")

实际业务场景应用

在生产环境中,这些中间件组件直接与监控系统集成。例如,Kubernetes 等容器平台可以通过 /healthz 接口检测应用存活,/readiness 则用于探测数据库和缓存的连接状态。这使得运维人员能够实时监控应用健康,及时发现潜在问题并响应。

同时,ApiLoggingMiddleware 提供的日志功能,使得开发和运维团队能够快速定位问题源。若某接口请求异常,管理员可以查询到相关的日志记录,包括请求参数、响应状态、调用来源等,帮助快速复现问题并解决。

例如,在一个用户登录接口的日志记录中,管理员可以看到:

POST /api/auth/login/

日志条目中将包含如下信息,请求 IP,请求参数(敏感字段如密码会被脱敏处理),操作系统、浏览器信息,接口响应状态码(例如 2000: 请求成功,5000: 系统错误)和请求路径和方法。

这些信息可以帮助开发者跟踪每一次请求的详细数据,并在生产环境中快速发现并排除错误。

这个实现方案有效地增强了系统的可观察性和可维护性,确保了服务的高可用性并提升了故障诊断能力。

总结

API 日志中间件通过统一拦截请求与响应,自动记录关键信息并脱敏处理,兼顾审计合规与数据安全。健康检查中间件以轻量接口快速反馈服务与依赖状态,适配主流容器编排平台。两者设计紧凑,嵌入简单,提升了系统可观测性和运维效率。

日志存储依赖同步数据库写入,高并发时可能拉低接口响应速度。健康探针接口缺乏分级策略,所有检查一律阻断响应,灵活性不足。若重写,应将日志写入异步队列处理,并引入分级健康探测,提升性能与故障应对能力。

你可能感兴趣的:(待分类-Web开发,django)