[025][Web模块]基于 Spring Boot 的请求日志过滤器设计与实现

简介: 本文介绍基于Spring Boot的可配置请求日志过滤器,通过自定义`WebHttpProperties`、扩展`CommonsRequestLoggingFilter`及自动配置类,支持时间戳、客户端信息、请求头/体记录、动态前缀等灵活配置,开箱即用,兼顾可维护性与生产安全性。(239字)

[025][Web模块]基于 Spring Boot 的请求日志过滤器设计与实现

1. 引言

在 Web 应用开发中,记录 HTTP 请求的详细信息对于问题排查、安全审计和性能分析至关重要。Spring Boot 内置的 CommonsRequestLoggingFilter 提供了基础的请求日志能力,但其功能较为有限(例如无法灵活添加时间戳、无法动态控制日志级别等)。本文介绍一种扩展实现——通过自定义配置属性、过滤器及自动配置,构建一个可配置、易集成的高灵活请求日志组件。

2. 整体设计

该组件包含三个核心类:

  • WebHttpProperties:集中管理 Web 层 HTTP 相关配置,其中嵌套了 RequestLoggingOptions 用于定制请求日志行为。
  • DefaultCommonsRequestLoggingFilter:继承 CommonsRequestLoggingFilter,重写关键方法以支持时间戳追加和强制日志记录。
  • WebMvcRequestLoggingConfiguration:Spring Boot 自动配置类,根据属性创建并注册过滤器 Bean。

整体架构图如下:

┌─────────────────────────────────────────────────────────┐
│                   application.yml                        │
│  tutorials4j.web.http.request-logging.*                  │
└───────────────────┬─────────────────────────────────────┘
                    │ @ConfigurationProperties
                    ▼
┌─────────────────────────────────────────────────────────┐
│                  WebHttpProperties                       │
│  ┌─────────────────────────────────────────────────┐    │
│  │ +RequestLoggingOptions                           │    │
│  │   - includeTimestamp                             │    │
│  │   - includeClientInfo / Headers / Payload        │    │
│  │   - maxPayloadLength, message prefixes...        │    │
│  └─────────────────────────────────────────────────┘    │
└───────────────────┬─────────────────────────────────────┘
                    │ 注入
                    ▼
┌─────────────────────────────────────────────────────────┐
│          WebMvcRequestLoggingConfiguration               │
│  @Bean FilterRegistrationBean<DefaultCommons...>        │
└───────────────────┬─────────────────────────────────────┘
                    │ 创建并初始化
                    ▼
┌─────────────────────────────────────────────────────────┐
│         DefaultCommonsRequestLoggingFilter              │
│  - 重写 createMessage() 追加 timestamp                  │
│  - 重写 shouldLog() 始终返回 true                       │
│  - init() 将 options 映射到父类属性                     │
└─────────────────────────────────────────────────────────┘

3. 核心组件详解

3.1 配置属性类 WebHttpProperties

该类使用 @ConfigurationProperties(prefix = "tutorials4j.web.http"),将外部配置绑定到结构化对象。其中 RequestLoggingOptions 内部类定义了以下关键配置项:

配置项 类型 默认值 说明
filter ServletFilterOptions name="requestLoggingServletFilter" 通用的过滤器注册参数(启用状态、URL 模式、顺序等)
includeTimestamp boolean false 是否在日志消息末尾追加当前毫秒时间戳
includeClientInfo boolean false 是否记录客户端地址、Session ID、用户信息
includeHeaders boolean false 是否记录请求头
includePayload boolean false 是否记录请求体内容
maxPayloadLength int 300 记录请求体的最大字符数
beforeMessagePrefix / suffix String "请求前 [" / "]" 请求处理前日志的前后缀
afterMessagePrefix / suffix String "请求后 [" / "]" 请求处理后日志的前后缀

设计亮点:通过嵌套 ServletFilterOptions,复用统一的过滤器注册配置(如设置 enabled、urlPatterns、order 等),避免重复代码。

3.2 自定义过滤器 DefaultCommonsRequestLoggingFilter

该类通过构造器注入 RequestLoggingOptions,并在 init() 方法中将配置同步到父类的各个 setter:

public void init() {
   
    setIncludeClientInfo(options.isIncludeClientInfo());
    setIncludeHeaders(options.isIncludeHeaders());
    setIncludePayload(options.isIncludePayload());
    setMaxPayloadLength(options.getMaxPayloadLength());
    setBeforeMessagePrefix(options.getBeforeMessagePrefix());
    setBeforeMessageSuffix(options.getBeforeMessageSuffix());
    setAfterMessagePrefix(options.getAfterMessagePrefix());
    setAfterMessageSuffix(options.getAfterMessageSuffix());
}

关键重写方法:

  • createMessage(..., String suffix):若 includeTimestamp == true,则在原 suffix 前插入 ", timestamp=" + System.currentTimeMillis(),使日志输出类似:
    请求前 [GET /api/user, timestamp=1746789123456]
  • shouldLog(HttpServletRequest):始终返回 true。父类默认会根据日志级别判断(需要 Logger 为 DEBUG),此处强制所有请求均尝试记录,最终是否输出仍取决于 CommonsRequestLoggingFilter 内部对 logger.isDebugEnabled() 的检查。

3.3 自动配置类 WebMvcRequestLoggingConfiguration

该配置类使用 @Configuration(proxyBeanMethods = false),提供轻量级的配置 Bean。核心方法 requestLoggingFilterRegistration 完成:

  1. 获取 RequestLoggingOptions 及其内部的 ServletFilterOptions。
  2. 实例化 DefaultCommonsRequestLoggingFilter 并调用 init()。
  3. 创建 FilterRegistrationBean,利用 ServletFilterOptions.fill(registration) 方法填充注册信息(如 setEnabled、setUrlPatterns、setOrder 等)。
  4. 如果过滤器启用,则主动获取 CommonsRequestLoggingFilter 的 Logger 并调用 isEnabledForLevel(Level.DEBUG)(该语句实际未改变日志级别,仅用于触发日志框架的状态初始化,属于框架适配的防御性代码)。
  5. 输出配置加载完成的 debug 日志。

4. 使用示例

4.1 Maven 依赖(假设已引入 tutorials4j 框架)

确保项目中包含 spring-boot-starter-web 及该框架模块。

4.2 配置文件 application.yml

tutorials4j:
  web:
    http:
      request-logging:
        enabled: true                     # 通过 filter.enabled 控制
        filter:
          url-patterns: "/api/*"          # 仅拦截 API 路径
          order: 1
        include-timestamp: true
        include-client-info: true
        include-headers: true
        include-payload: true
        max-payload-length: 500
        before-message-prefix: ">>> "
        after-message-prefix: "<<< "

4.3 日志输出示例(Level = DEBUG)

>>> GET /api/user/123, client=0:0:0:0:0:0:0:1, headers=[User-Agent: Mozilla/5.0...], timestamp=1746789123456
<<< GET /api/user/123, status=200, timestamp=1746789123789

5. 扩展与定制

5.1 动态控制日志记录

当前 shouldLog() 固定返回 true,如需根据请求特征(如 URL、IP、用户角色)动态决定是否记录,可进一步重写该方法:

@Override
protected boolean shouldLog(HttpServletRequest request) {
   
    return options.isEnabled() && !request.getRequestURI().contains("/health");
}

5.2 添加更多元数据

在 createMessage 中除了时间戳,还可添加请求耗时、TraceId 等信息:

String traceId = MDC.get("traceId");
if (traceId != null) {
   
    newsuffix = ", traceId=" + traceId + newsuffix;
}

5.3 自定义日志输出目标

CommonsRequestLoggingFilter 默认使用 org.springframework.web.filter.CommonsRequestLoggingFilter 为 Logger 名。可以重写 getLogger() 方法,指定独立的 Logger 名称,以便分离日志文件。

6. 注意事项

  • 性能影响:记录请求体(includePayload=true)时,会读取 InputStream 并可能缓存,对大型请求有内存开销。合理设置 maxPayloadLength 并避免记录文件上传接口。
  • 敏感信息:请求头或 body 中可能包含密码、Token 等敏感数据,生产环境应关闭 includeHeaders 和 includePayload,或通过自定义 createMessage 进行脱敏。
  • 日志级别:CommonsRequestLoggingFilter 内部使用 logger.isDebugEnabled() 判断是否输出。因此必须将对应 Logger 的级别设为 DEBUG,例如在 application.yml:
    logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG
    

7. 总结

本文介绍的请求日志组件基于 Spring Boot 的扩展机制,实现了:

  • 配置驱动:通过 @ConfigurationProperties 将繁杂的过滤器参数外部化。
  • 功能增强:支持时间戳、灵活的 message 格式和强制日志记录策略。
  • 集成友好:通过 FilterRegistrationBean 注入,可与现有安全、监控过滤器链无缝协作。

该组件适用于需要统一请求日志规范的中大型项目,开发者可根据业务需求轻松调整其行为。完整代码已集成在 tutorials4j 框架中,开箱即用。

目录
相关文章
|
3月前
|
JSON 安全 Java
[024][Web模块]基于 AntiSamy 的 Spring Boot XSS 防护实践:从过滤器到反序列化的多层防御
本文介绍基于OWASP AntiSamy的Spring Boot XSS多层防护方案:通过Servlet过滤器清洗表单/查询参数,结合Jackson反序列化器净化JSON数据,实现非侵入、全覆盖的输入清洗,业务代码零修改。(239字)
428 2
|
3月前
|
人工智能 算法 大数据
年薪$60万赶超ML研究员?拆解Palantir“FDE+Echo”双引擎如何跨越AI落地死亡谷
Palantir“FDE+Echo”双引擎破解AI落地困局:95%试点失败源于旧系统“屎山”与业务脱节。Echo(行业专家)精准定义问题,Delta(FDE工程师)现场构建本体模型、打通脏数据。通过“定制→标准→规模化”飞轮,实现工程工时指数级下降,跨越AI死亡谷。
466 1
|
3月前
|
前端开发 Java API
[049][Crypto模块]前后端混合加密API实战:基于Spring Boot的AES+RSA安全传输方案
本文详解Spring Boot中AES+RSA混合加密实战:前端用RSA公钥加密随机AES密钥并传输,后端通过`@Crypto`注解自动解密请求体。涵盖公钥分发、Hex/Base64编码统一、ECB模式适配及Caffeine缓存优化,提供开箱即用的端到端安全传输方案。(239字)
383 0
|
3月前
|
设计模式 Java Spring
[046][Crypto模块]Spring Boot 自动配置进阶:按需装配加解密处理器
本文详解Spring Boot自动配置进阶实践:基于Crypto模块,通过`@ConditionalOnMissingBean`、`@EnableConfigurationProperties`等注解,实现加解密处理器的按需装配与灵活覆盖。涵盖配置属性绑定、多配置类拆分、条件加载(Web/非Web)、日志调试及Hutool集成,助力构建高可扩展Starter。
224 2
|
3月前
|
SQL Java 数据库连接
[026][数据模块]基于 MyBatis Plus 的企业级数据访问框架设计与实现
本文介绍基于MyBatis Plus二次封装的企业级数据访问框架,支持多租户隔离、分页、乐观锁、SQL防攻击及审计字段自动填充。通过有序拦截器链、条件化配置与开放扩展点,实现可插拔、易维护的统一数据访问能力。(239字)
206 2
|
3月前
|
算法 安全 Java
[047][Crypto模块]基于 Hutool 的常见加解密算法封装与密钥自动生成
本文基于Hutool封装统一加解密框架,提供AES/RSA/SM2/SM4/HMAC等算法的`CryptoProcessor`标准接口,支持密钥自动生成与动态切换,解耦业务代码,兼顾国密合规与易用性,提升安全性与可测试性。(239字)
160 1
|
3月前
|
算法 Java 数据安全/隐私保护
[045][Crypto模块]设计一个可扩展的加解密框架:策略模式与工厂模式实战
本文基于Spring Boot,运用策略模式与工厂模式设计可扩展加解密框架:统一`CryptoProcessor`接口封装AES、RSA、SM2等算法;通过`CryptoProcessorFactory`按枚举类别自动注册/查找处理器;结合Spring自动装配,新增算法(如SM9)仅需实现接口并声明Bean,零侵入扩展。高内聚、低耦合、易维护。(239字)
240 2
|
6月前
|
存储 人工智能 Java
AI实践|基于 Spring AI 从0到1构建 AI Agent
文章内容基于作者个人技术实践与独立思考,旨在分享经验,仅代表个人观点。
AI实践|基于 Spring AI 从0到1构建 AI Agent
|
6月前
|
缓存 Java API
从原理到落地:RAG 技术深度拆解与 Java 实战全攻略
RAG(检索增强生成)是解决大模型知识时效性差、易幻觉的核心方案:通过实时检索私有/外部数据,将其作为上下文输入大模型,实现准确、可更新的回答。相比微调,RAG成本低、上线快、维护简,是企业落地LLM的首选架构。
422 1

热门文章

最新文章