拦截过滤器模式(长文解析)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;演示链接: http://116.62.199.48:7070 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观
前言
在软件开发中,我们经常需要对请求进行预处理或后处理。例如,Web应用可能需要在处理用户请求前验证身份、记录日志,或在响应生成后压缩数据。拦截过滤器模式(Interceptor Filter Pattern)正是为这类场景设计的解决方案,它提供了一种结构化、可扩展的方式,将请求处理流程分解为一系列可组合的过滤器。本文将通过通俗的比喻、代码示例和实际案例,帮助读者理解这一模式的核心思想及应用场景。
核心概念:什么是拦截过滤器模式?
拦截过滤器模式属于结构型设计模式,其核心思想是将请求的处理流程拆解为多个独立的“过滤器”(Filter)。每个过滤器负责完成特定的处理任务(如权限校验、日志记录),并决定是否将请求传递给下一个过滤器。这种设计使得系统能够灵活组合处理逻辑,避免单点代码的臃肿。
关键组成部分
- Filter(过滤器):
- 具体执行处理逻辑的对象,如“身份验证过滤器”或“请求日志过滤器”。
- 每个过滤器通常包含一个
doFilter()
方法,接收请求对象和过滤器链(Filter Chain)。
- Filter Chain(过滤器链):
- 管理过滤器的执行顺序,并将请求依次传递给链中的下一个过滤器。
- Request/Response 对象:
- 请求和响应的载体,可能被过滤器修改或增强。
类比解释
想象机场安检流程:旅客(请求)经过多个检查站(过滤器),每个检查站执行不同任务(如证件验证、行李扫描)。每个检查站处理完后,若无异常,将旅客传递给下一个检查站。这个流程与拦截过滤器模式的运作方式高度相似。
工作原理:过滤器链如何运作?
拦截过滤器模式的核心是链式调用。以下是其典型工作流程:
- 请求进入过滤器链:客户端发送请求后,首先由过滤器链接收。
- 执行过滤器:
- 过滤器链依次调用每个过滤器的
doFilter()
方法。 - 每个过滤器可以选择:
- 直接处理请求(如记录日志);
- 修改请求内容(如解密参数);
- 终止请求(如拒绝未授权用户)。
- 过滤器链依次调用每个过滤器的
- 传递给下一个过滤器:若当前过滤器未终止请求,它会调用过滤器链的
next()
方法,将控制权交给下一个过滤器。 - 最终处理请求:当所有过滤器执行完毕,请求会被传递给目标资源(如控制器或服务)。
流程图示意
阶段 | 描述 |
---|---|
过滤器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框架,需要实现以下功能:
- 检查请求头中的
Authorization
字段; - 记录所有请求的路径和时间戳;
- 压缩响应数据(仅对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安全还是文件处理,该模式都能帮助开发者构建清晰、扩展性强的系统。掌握这一模式后,读者可以尝试将其应用于自己的项目,例如为现有代码添加日志记录或性能监控功能。
通过本文的代码示例和案例分析,希望读者能够理解拦截过滤器模式的核心思想,并在实践中灵活运用这一设计模式,提升代码的模块化和可维护性。