拦截过滤器模式(长文解析)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在软件开发中,我们经常需要对请求进行预处理或后处理。例如,Web应用可能需要在处理用户请求前验证身份、记录日志,或在响应生成后压缩数据。拦截过滤器模式(Interceptor Filter Pattern)正是为这类场景设计的解决方案,它提供了一种结构化、可扩展的方式,将请求处理流程分解为一系列可组合的过滤器。本文将通过通俗的比喻、代码示例和实际案例,帮助读者理解这一模式的核心思想及应用场景。


核心概念:什么是拦截过滤器模式?

拦截过滤器模式属于结构型设计模式,其核心思想是将请求的处理流程拆解为多个独立的“过滤器”(Filter)。每个过滤器负责完成特定的处理任务(如权限校验、日志记录),并决定是否将请求传递给下一个过滤器。这种设计使得系统能够灵活组合处理逻辑,避免单点代码的臃肿。

关键组成部分

  1. Filter(过滤器)
    • 具体执行处理逻辑的对象,如“身份验证过滤器”或“请求日志过滤器”。
    • 每个过滤器通常包含一个doFilter()方法,接收请求对象和过滤器链(Filter Chain)。
  2. Filter Chain(过滤器链)
    • 管理过滤器的执行顺序,并将请求依次传递给链中的下一个过滤器。
  3. Request/Response 对象
    • 请求和响应的载体,可能被过滤器修改或增强。

类比解释

想象机场安检流程:旅客(请求)经过多个检查站(过滤器),每个检查站执行不同任务(如证件验证、行李扫描)。每个检查站处理完后,若无异常,将旅客传递给下一个检查站。这个流程与拦截过滤器模式的运作方式高度相似。


工作原理:过滤器链如何运作?

拦截过滤器模式的核心是链式调用。以下是其典型工作流程:

  1. 请求进入过滤器链:客户端发送请求后,首先由过滤器链接收。
  2. 执行过滤器
    • 过滤器链依次调用每个过滤器的doFilter()方法。
    • 每个过滤器可以选择:
      • 直接处理请求(如记录日志);
      • 修改请求内容(如解密参数);
      • 终止请求(如拒绝未授权用户)。
  3. 传递给下一个过滤器:若当前过滤器未终止请求,它会调用过滤器链的next()方法,将控制权交给下一个过滤器。
  4. 最终处理请求:当所有过滤器执行完毕,请求会被传递给目标资源(如控制器或服务)。

流程图示意

阶段描述
过滤器1执行身份验证,若失败则中断流程
过滤器2记录请求日志
过滤器3压缩响应数据
目标资源处理核心业务逻辑

实现步骤:手把手构建一个拦截过滤器系统

以下是一个基于Python的简化实现,帮助读者理解模式的核心逻辑:

1. 定义过滤器接口

class Filter:  
    def __init__(self, next_filter=None):  
        self.next = next_filter  # 下一个过滤器  

    def do_filter(self, request, response):  
        # 预处理逻辑(可选)  
        self._pre_handle(request, response)  
        # 调用下一个过滤器  
        if self.next:  
            self.next.do_filter(request, response)  
        # 后处理逻辑(可选)  
        self._post_handle(request, response)  

    def _pre_handle(self, request, response):  
        pass  

    def _post_handle(self, request, response):  
        pass  

2. 创建具体过滤器

身份验证过滤器

class AuthenticationFilter(Filter):  
    def _pre_handle(self, request, response):  
        if not request.is_authenticated:  
            response.error = "Unauthorized"  
            self.next = None  # 终止后续过滤器  

日志记录过滤器

class LoggingFilter(Filter):  
    def _pre_handle(self, request, response):  
        print(f"Request received: {request.path}")  

3. 构建过滤器链

auth_filter = AuthenticationFilter()  
logging_filter = LoggingFilter()  

auth_filter.next = logging_filter  # 认证 → 日志记录  

class Request:  
    def __init__(self, path, is_authenticated):  
        self.path = path  
        self.is_authenticated = is_authenticated  

class Response:  
    def __init__(self):  
        self.error = None  

request = Request("/api/data", is_authenticated=False)  
response = Response()  

auth_filter.do_filter(request, response)  
print("Final response error:", response.error)  # 输出:Unauthorized  

实际案例:拦截过滤器在Web框架中的应用

场景:REST API 鉴权与日志

假设我们开发一个小型Web框架,需要实现以下功能:

  1. 检查请求头中的Authorization字段;
  2. 记录所有请求的路径和时间戳;
  3. 压缩响应数据(仅对JSON响应生效)。

过滤器实现

class AuthFilter(Filter):  
    def _pre_handle(self, req, res):  
        auth_header = req.headers.get("Authorization")  
        if not auth_header or not self._validate_token(auth_header):  
            res.status = 401  
            res.body = {"error": "Unauthorized"}  
            self.next = None  # 终止链  

    def _validate_token(self, token):  
        # 简化验证逻辑  
        return token == "secret_token"  

class LoggingFilter(Filter):  
    def _pre_handle(self, req, res):  
        print(f"[{datetime.now()}] {req.method} {req.path}")  

class GzipFilter(Filter):  
    def _post_handle(self, req, res):  
        if "application/json" in req.headers.get("Accept", ""):  
            res.body = gzip.compress(json.dumps(res.body).encode())  
            res.headers["Content-Encoding"] = "gzip"  

过滤器链配置

auth_filter = AuthFilter()  
logging_filter = LoggingFilter()  
gzip_filter = GzipFilter()  

auth_filter.next = logging_filter  
logging_filter.next = gzip_filter  

常见问题与最佳实践

问题1:如何避免过滤器链中的循环引用?

确保每个过滤器仅持有下一个过滤器的引用,而非形成闭环。例如,避免Filter A → Filter B → Filter A

问题2:过滤器如何处理异常?

在过滤器的预处理或后处理阶段,可以捕获异常并记录,同时终止链的执行。例如:

def _pre_handle(self, req, res):  
    try:  
        # 可能抛出异常的逻辑  
    except Exception as e:  
        res.error = str(e)  
        self.next = None  # 终止链  

最佳实践

  • 保持过滤器单一职责:每个过滤器只做一件事(如仅处理日志或仅验证权限)。
  • 按顺序排列过滤器:将关键过滤器(如鉴权)放在链的前端,避免无效处理。
  • 异步支持:在高性能场景中,可将过滤器改为异步函数,提升吞吐量。

适用场景与模式对比

典型应用场景

  • Web请求处理:身份验证、CORS头设置、内容类型协商。
  • API网关:限流、熔断、请求路由。
  • 文件处理:格式转换、压缩、加密。

与责任链模式的区别

拦截过滤器模式与责任链模式(Chain of Responsibility)有相似之处,但核心目标不同:

  • 拦截过滤器:专注于预处理和后处理,请求最终会到达目标资源(除非被拦截)。
  • 责任链模式:请求由链中第一个能处理它的对象处理,无需到达终点。

结论

拦截过滤器模式通过将请求处理流程分解为可组合的过滤器,提供了高度的灵活性和可维护性。无论是Web开发、API安全还是文件处理,该模式都能帮助开发者构建清晰、扩展性强的系统。掌握这一模式后,读者可以尝试将其应用于自己的项目,例如为现有代码添加日志记录或性能监控功能。

通过本文的代码示例和案例分析,希望读者能够理解拦截过滤器模式的核心思想,并在实践中灵活运用这一设计模式,提升代码的模块化和可维护性。

最新发布