【SpringBoot请求记录】Spring Boot Actuator 自定义记录 HTTP 服务请求

Spring Boot Actuator 自定义记录 HTTP 服务请求

1. 概述

在 Spring Boot 项目中,如果需要完整记录 HTTP 服务请求,例如:

  • 请求方式:GET、POST、PUT、DELETE
  • 请求地址
  • QueryString
  • Request Body
  • Response Body
  • HTTP 状态码
  • 请求耗时
  • 客户端 IP
  • User-Agent
  • TraceId
  • 异常请求

推荐采用:

text 复制代码
Spring Boot Actuator
        +
OncePerRequestFilter
        +
ContentCachingRequestWrapper
        +
ContentCachingResponseWrapper

需要特别注意:

Spring Boot Actuator 本身并不适合直接记录完整的 Request Body 和 Response Body。

Actuator 更适合提供:

  • 健康检查
  • JVM 指标
  • HTTP 请求指标
  • 自定义监控端点

而 HTTP 请求、响应内容的采集建议通过 Filter 完成。

最终架构如下:

text 复制代码
                    HTTP Request
                         │
                         ▼
              ┌─────────────────────┐
              │ RequestLogFilter    │
              │ OncePerRequestFilter│
              └──────────┬──────────┘
                         │
                         ▼
          ContentCachingRequestWrapper
          ContentCachingResponseWrapper
                         │
                         ▼
                 Spring MVC Controller
                         │
                         ▼
                    Service层
                         │
                         ▼
                    Response
                         │
                         ▼
                 Filter获取Body
                         │
                         ▼
                   RequestLog
                         │
                         ▼
                 异步保存 / 日志系统
                         │
                         ▼
             /actuator/request-logs

2. 添加 Spring Boot Actuator

Maven 添加:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

如果项目同时使用 Spring MVC:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

3. 配置 Actuator

application.yml

yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include:
          - health
          - info
          - metrics
          - loggers

  endpoint:
    health:
      show-details: always

启动项目后访问:

text 复制代码
http://localhost:8080/actuator

可以看到 Actuator 暴露的端点。

例如:

text 复制代码
/actuator
/actuator/health
/actuator/info
/actuator/metrics
/actuator/loggers

4. 为什么不能直接读取 HttpServletRequest Body

很多人会在 Filter 中直接:

java 复制代码
InputStream inputStream = request.getInputStream();

String body = new String(
        inputStream.readAllBytes(),
        StandardCharsets.UTF_8
);

这种方式存在严重问题。

HTTP Request Body 本质上是一个输入流。

如果 Filter 首先读取:

text 复制代码
HTTP Request
      │
      ▼
Filter
      │
      ▼
读取 InputStream
      │
      ▼
Controller
      │
      ▼
@RequestBody

那么 Controller 再读取 Body 时可能已经没有数据。

例如:

java 复制代码
@PostMapping("/user")
public User add(@RequestBody User user) {
    return user;
}

可能出现:

text 复制代码
Request Body 已经被 Filter 消耗
            ↓
@RequestBody 无法读取
            ↓
JSON 解析失败

因此应该使用:

java 复制代码
ContentCachingRequestWrapper

5. ContentCachingRequestWrapper

Spring 提供:

java 复制代码
org.springframework.web.util.ContentCachingRequestWrapper

它可以在 Request Body 被业务代码读取后,将内容缓存起来。

执行过程:

text 复制代码
HTTP Request
      │
      ▼
ContentCachingRequestWrapper
      │
      ├──────────────► Controller读取Body
      │
      ▼
缓存Request Body
      │
      ▼
Filter读取缓存

因此 Filter 可以在业务代码执行完成之后:

java 复制代码
requestWrapper.getContentAsByteArray()

获取 Request Body。


6. ContentCachingResponseWrapper

Response 同样存在类似问题。

Spring 提供:

java 复制代码
org.springframework.web.util.ContentCachingResponseWrapper

它可以缓存 Controller 返回的 Response Body。

使用:

java 复制代码
ContentCachingResponseWrapper responseWrapper =
        new ContentCachingResponseWrapper(response);

业务执行:

java 复制代码
filterChain.doFilter(requestWrapper, responseWrapper);

然后:

java 复制代码
byte[] body = responseWrapper.getContentAsByteArray();

获取 Response Body。

最后必须:

java 复制代码
responseWrapper.copyBodyToResponse();

否则可能导致客户端收不到正常的响应内容。


7. 最简单的 RequestLogFilter

创建:

text 复制代码
src/main/java/com/example/demo/filter/RequestLogFilter.java

代码:

java 复制代码
package com.example.demo.filter;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Component
public class RequestLogFilter extends OncePerRequestFilter {

    @Override
    protected boolean shouldNotFilter(HttpServletRequest request) {

        // 不记录 Actuator 自身请求
        return request.getRequestURI().startsWith("/actuator/");
    }

    @Override
    protected void doFilterInternal(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain filterChain)
            throws ServletException, IOException {

        ContentCachingRequestWrapper requestWrapper =
                new ContentCachingRequestWrapper(request);

        ContentCachingResponseWrapper responseWrapper =
                new ContentCachingResponseWrapper(response);

        long startTime = System.currentTimeMillis();

        try {

            // 执行业务代码
            filterChain.doFilter(
                    requestWrapper,
                    responseWrapper
            );

        } finally {

            long cost =
                    System.currentTimeMillis() - startTime;

            String queryString =
                    requestWrapper.getQueryString();

            String requestBody =
                    getRequestBody(requestWrapper);

            String responseBody =
                    getResponseBody(responseWrapper);

            System.out.println("================ HTTP REQUEST ================");

            System.out.println(
                    "Method      : "
                            + requestWrapper.getMethod()
            );

            System.out.println(
                    "URI         : "
                            + requestWrapper.getRequestURI()
            );

            System.out.println(
                    "QueryString : "
                            + queryString
            );

            System.out.println(
                    "RequestBody : "
                            + requestBody
            );

            System.out.println(
                    "Status      : "
                            + responseWrapper.getStatus()
            );

            System.out.println(
                    "ResponseBody: "
                            + responseBody
            );

            System.out.println(
                    "Cost        : "
                            + cost
                            + " ms"
            );

            System.out.println("==============================================");

            // 非常重要
            responseWrapper.copyBodyToResponse();
        }
    }

    /**
     * 获取 Request Body
     */
    private String getRequestBody(
            ContentCachingRequestWrapper request) {

        byte[] content =
                request.getContentAsByteArray();

        if (content.length == 0) {
            return "";
        }

        return new String(
                content,
                StandardCharsets.UTF_8
        );
    }

    /**
     * 获取 Response Body
     */
    private String getResponseBody(
            ContentCachingResponseWrapper response) {

        byte[] content =
                response.getContentAsByteArray();

        if (content.length == 0) {
            return "";
        }

        return new String(
                content,
                StandardCharsets.UTF_8
        );
    }
}

8. GET 请求记录

例如:

http 复制代码
GET /api/user/list?page=1&size=20

Filter 可以获取:

text 复制代码
Method      : GET
URI         : /api/user/list
QueryString : page=1&size=20
RequestBody :

如果需要完整 URL:

java 复制代码
String url = requestWrapper.getRequestURL().toString();

String queryString = requestWrapper.getQueryString();

if (queryString != null && !queryString.isEmpty()) {
    url += "?" + queryString;
}

最终:

text 复制代码
http://localhost:8080/api/user/list?page=1&size=20

9. POST JSON 请求

例如:

http 复制代码
POST /api/user/add
Content-Type: application/json

Request Body:

json 复制代码
{
    "name": "张三",
    "age": 20
}

Filter 可以记录:

text 复制代码
Method      : POST
URI         : /api/user/add
QueryString :
RequestBody : {"name":"张三","age":20}

Status      : 200
ResponseBody: {"code":200,"message":"success"}

Cost        : 18 ms

10. QueryString + Body

如果要求:

请求参数 = QueryString + Request Body

建议不要简单拼接成字符串,而是结构化保存。

例如:

json 复制代码
{
  "method": "POST",
  "uri": "/api/user/add",
  "queryString": "source=web&version=1",
  "requestBody": {
    "name": "张三",
    "age": 20
  },
  "responseBody": {
    "code": 200,
    "message": "success"
  }
}

这样后续存储到:

  • MySQL
  • Elasticsearch
  • MongoDB
  • Loki
  • ClickHouse

都会更加方便。


11. 定义 RequestLog 对象

建议定义统一的日志对象:

java 复制代码
package com.example.demo.model;

import lombok.Builder;
import lombok.Data;

import java.time.LocalDateTime;

@Data
@Builder
public class RequestLog {

    /**
     * 请求时间
     */
    private LocalDateTime requestTime;

    /**
     * 请求方式
     */
    private String method;

    /**
     * 请求地址
     */
    private String uri;

    /**
     * QueryString
     */
    private String queryString;

    /**
     * Request Body
     */
    private String requestBody;

    /**
     * Response Body
     */
    private String responseBody;

    /**
     * HTTP状态码
     */
    private Integer status;

    /**
     * 请求耗时
     */
    private Long cost;

    /**
     * 客户端IP
     */
    private String clientIp;

    /**
     * User-Agent
     */
    private String userAgent;

    /**
     * TraceId
     */
    private String traceId;
}

12. 在 Filter 中构建 RequestLog

java 复制代码
RequestLog log = RequestLog.builder()
        .requestTime(LocalDateTime.now())
        .method(requestWrapper.getMethod())
        .uri(requestWrapper.getRequestURI())
        .queryString(requestWrapper.getQueryString())
        .requestBody(getRequestBody(requestWrapper))
        .responseBody(getResponseBody(responseWrapper))
        .status(responseWrapper.getStatus())
        .cost(cost)
        .clientIp(requestWrapper.getRemoteAddr())
        .userAgent(requestWrapper.getHeader("User-Agent"))
        .traceId(getTraceId(requestWrapper))
        .build();

然后交给:

java 复制代码
requestLogService.save(log);

13. 获取客户端 IP

最简单:

java 复制代码
request.getRemoteAddr();

但是如果系统部署在:

text 复制代码
Nginx
    ↓
Gateway
    ↓
Spring Boot

那么:

java 复制代码
request.getRemoteAddr()

可能得到的是:

text 复制代码
127.0.0.1

而不是用户真实 IP。

可以根据实际代理配置读取:

java 复制代码
private String getClientIp(HttpServletRequest request) {

    String ip = request.getHeader("X-Forwarded-For");

    if (ip == null || ip.isEmpty()) {
        ip = request.getHeader("X-Real-IP");
    }

    if (ip == null || ip.isEmpty()) {
        ip = request.getRemoteAddr();
    }

    return ip;
}

生产环境需要结合网关/Nginx的可信代理配置,避免客户端伪造这些 Header。


14. TraceId

微服务系统强烈建议增加:

text 复制代码
TraceId

例如:

text 复制代码
用户请求
   │
   ▼
Gateway
   │
   │ traceId=abc123
   ▼
User Service
   │
   ▼
Order Service
   │
   ▼
Payment Service

所有服务日志:

text 复制代码
traceId=abc123

这样可以快速定位一次完整请求经过了哪些服务。

如果项目使用:

text 复制代码
Micrometer Tracing

可以直接接入 TraceId。


15. 文件上传必须特殊处理

不能直接记录:

http 复制代码
POST /upload
Content-Type: multipart/form-data

因为文件可能达到:

text 复制代码
10 MB
100 MB
1 GB

如果全部缓存:

java 复制代码
getContentAsByteArray()

可能造成:

text 复制代码
内存暴涨
    ↓
GC频繁
    ↓
OOM

建议:

java 复制代码
private boolean isFileUpload(
        HttpServletRequest request) {

    String contentType =
            request.getContentType();

    return contentType != null
            && contentType.startsWith("multipart/");
}

记录:

text 复制代码
RequestBody: [FILE_UPLOAD]

而不是实际文件内容。


16. Body 大小限制

建议限制最大记录长度。

例如:

java 复制代码
private static final int MAX_BODY_SIZE = 10 * 1024;

实现:

java 复制代码
private String getRequestBody(
        ContentCachingRequestWrapper request) {

    byte[] content =
            request.getContentAsByteArray();

    if (content.length == 0) {
        return "";
    }

    if (content.length > MAX_BODY_SIZE) {

        return new String(
                content,
                0,
                MAX_BODY_SIZE,
                StandardCharsets.UTF_8
        ) + "...[TRUNCATED]";
    }

    return new String(
            content,
            StandardCharsets.UTF_8
    );
}

Response Body 同样建议限制。


17. 敏感数据脱敏

这是生产环境必须考虑的问题。

例如请求:

json 复制代码
{
    "username": "zhangsan",
    "password": "123456",
    "token": "eyJhbGci...",
    "phone": "13800138000"
}

不能直接保存成日志。

应该:

json 复制代码
{
    "username": "zhangsan",
    "password": "***",
    "token": "***",
    "phone": "138****8000"
}

建议至少处理:

text 复制代码
password
passwd
token
access_token
refresh_token
authorization
cookie
secret
apiKey
idCard
phone
bankCard

18. Authorization 不建议记录

例如:

http 复制代码
Authorization: Bearer eyJhbGciOi...

这个 Header 本质上可能就是用户的认证凭证。

因此不建议把:

text 复制代码
Authorization
Cookie
Set-Cookie

直接写入请求日志。

如果确实需要记录 Header,应当做白名单:

java 复制代码
private static final Set<String> ALLOWED_HEADERS =
        Set.of(
                "Content-Type",
                "Accept",
                "User-Agent"
        );

而不是记录所有 Header。


19. 不要在 Filter 中同步写数据库

不推荐:

java 复制代码
finally {

    requestLogRepository.save(log);

}

请求执行过程:

text 复制代码
HTTP Request
      ↓
业务代码
      ↓
业务数据库
      ↓
请求日志数据库
      ↓
HTTP Response

这样会增加接口响应时间。

更严重的是:

text 复制代码
1000 QPS

意味着日志数据库可能同时承受:

text 复制代码
1000 次/秒

的写入。


20. 使用 @Async 异步保存

简单方案可以:

java 复制代码
@Service
public class RequestLogService {

    @Async
    public void save(RequestLog log) {

        requestLogRepository.save(log);
    }
}

启动:

java 复制代码
@EnableAsync
@SpringBootApplication
public class Application {
}

Filter:

java 复制代码
requestLogService.save(log);

这样 HTTP 请求线程不需要等待日志数据库操作完成。


21. 生产环境更推荐消息队列

如果系统请求量比较大:

text 复制代码
HTTP
 │
 ▼
RequestLogFilter
 │
 ▼
RequestLog
 │
 ▼
Kafka / RabbitMQ / Redis Stream
 │
 ▼
Log Consumer
 │
 ├── MySQL
 ├── Elasticsearch
 └── ClickHouse

优势:

text 复制代码
业务请求
   │
   ▼
快速完成日志投递
   │
   ▼
异步消费
   │
   ▼
持久化

避免日志数据库异常直接影响业务请求。


22. 自定义 Actuator Endpoint

如果希望通过:

text 复制代码
/actuator/request-logs

查看请求日志,可以创建自定义 Endpoint。

java 复制代码
package com.example.demo.actuator;

import com.example.demo.model.RequestLog;
import com.example.demo.service.RequestLogService;
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Endpoint(id = "request-logs")
public class RequestLogEndpoint {

    private final RequestLogService requestLogService;

    public RequestLogEndpoint(
            RequestLogService requestLogService) {
        this.requestLogService = requestLogService;
    }

    @ReadOperation
    public List<RequestLog> logs() {

        return requestLogService.findLatest(100);
    }
}

23. 暴露自定义 Endpoint

application.yml

yaml 复制代码
management:
  endpoints:
    web:
      exposure:
        include:
          - health
          - info
          - metrics
          - loggers
          - request-logs

然后访问:

text 复制代码
GET /actuator/request-logs

返回:

json 复制代码
[
  {
    "requestTime": "2026-09-04T08:30:12",
    "method": "POST",
    "uri": "/api/user",
    "queryString": "id=100",
    "requestBody": "{\"name\":\"张三\"}",
    "responseBody": "{\"code\":200}",
    "status": 200,
    "cost": 32,
    "clientIp": "192.168.1.10",
    "traceId": "abc123"
  }
]

24. Spring Boot Actuator 的职责

需要明确区分:

text 复制代码
                    HTTP监控体系
                         │
          ┌──────────────┴──────────────┐
          │                             │
          ▼                             ▼
     请求日志采集                   Actuator
          │                             │
          ▼                             ▼
    Filter + Wrapper              Metrics / Health
          │                             │
          ▼                             ▼
 Request Body                  请求数量
 Response Body                 请求耗时
 URL                           JVM
 QueryString                   数据库连接
 Status                        系统健康

Actuator 更适合:

text 复制代码
/actuator/health
/actuator/info
/actuator/metrics
/actuator/loggers

而完整 HTTP Body 日志应该由:

text 复制代码
Filter

完成。


25. 推荐的最终项目结构

建议:

text 复制代码
src/main/java
└── com.example.demo
    │
    ├── actuator
    │   └── RequestLogEndpoint.java
    │
    ├── filter
    │   └── RequestLogFilter.java
    │
    ├── model
    │   └── RequestLog.java
    │
    ├── service
    │   └── RequestLogService.java
    │
    ├── mapper
    │   └── RequestLogMapper.java
    │
    └── Application.java

26. 推荐的完整请求日志字段

生产环境建议至少保存:

字段 说明
id 日志ID
request_time 请求时间
trace_id 链路ID
method 请求方式
uri 请求地址
query_string QueryString
request_body Request Body
response_body Response Body
status HTTP状态码
cost 请求耗时
client_ip 客户端IP
user_agent User-Agent
user_id 当前用户ID
exception 异常信息
created_at 创建时间

27. 数据库表设计示例

如果使用 MySQL:

sql 复制代码
CREATE TABLE sys_request_log (
    id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',

    request_time DATETIME NOT NULL COMMENT '请求时间',

    trace_id VARCHAR(64) DEFAULT NULL COMMENT 'TraceId',

    method VARCHAR(20) DEFAULT NULL COMMENT '请求方式',

    uri VARCHAR(1000) DEFAULT NULL COMMENT '请求地址',

    query_string TEXT COMMENT 'QueryString',

    request_body MEDIUMTEXT COMMENT 'Request Body',

    response_body MEDIUMTEXT COMMENT 'Response Body',

    status INT DEFAULT NULL COMMENT 'HTTP状态码',

    cost BIGINT DEFAULT NULL COMMENT '请求耗时,单位ms',

    client_ip VARCHAR(128) DEFAULT NULL COMMENT '客户端IP',

    user_agent VARCHAR(1000) DEFAULT NULL COMMENT 'User-Agent',

    user_id VARCHAR(64) DEFAULT NULL COMMENT '用户ID',

    exception TEXT COMMENT '异常信息',

    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY (id),

    KEY idx_trace_id (trace_id),

    KEY idx_request_time (request_time),

    KEY idx_uri (uri),

    KEY idx_status (status)
) ENGINE=InnoDB
DEFAULT CHARSET=utf8mb4
COMMENT='HTTP请求日志';

28. 异常请求也必须记录

Filter 推荐使用:

java 复制代码
try {

    filterChain.doFilter(
            requestWrapper,
            responseWrapper
    );

} finally {

    // 记录日志

    responseWrapper.copyBodyToResponse();
}

不要只在:

java 复制代码
try

里面记录。

因为 Controller 可能出现:

text 复制代码
RuntimeException
BusinessException
NullPointerException
SQLException

如果日志只写在正常流程:

java 复制代码
filterChain.doFilter();

saveLog();

异常情况下:

text 复制代码
Controller异常
    ↓
saveLog()不会执行

最终最需要排查的异常请求反而没有日志。

因此建议:

text 复制代码
try
    ↓
执行请求
    ↓
finally
    ↓
无论成功失败都记录

29. 不建议记录的请求

建议配置 URL 黑名单:

text 复制代码
/actuator/**
/swagger-ui/**
/v3/api-docs/**
/favicon.ico
/static/**

例如:

java 复制代码
@Override
protected boolean shouldNotFilter(
        HttpServletRequest request) {

    String uri = request.getRequestURI();

    return uri.startsWith("/actuator/")
            || uri.startsWith("/swagger-ui/")
            || uri.startsWith("/v3/api-docs/")
            || uri.equals("/favicon.ico");
}

30. Body 类型建议过滤

不是所有请求都适合记录 Body。

建议:

记录

text 复制代码
application/json
application/xml
application/x-www-form-urlencoded
text/plain

不记录

text 复制代码
multipart/form-data
application/octet-stream
image/*
video/*
audio/*

可以:

java 复制代码
private boolean shouldRecordBody(
        HttpServletRequest request) {

    String contentType =
            request.getContentType();

    if (contentType == null) {
        return false;
    }

    return contentType.startsWith("application/json")
            || contentType.startsWith("application/xml")
            || contentType.startsWith("application/x-www-form-urlencoded")
            || contentType.startsWith("text/");
}

31. 推荐最终架构

对于一般企业级 Spring Boot 项目,推荐:

text 复制代码
                         Client
                           │
                           ▼
                    Nginx / Gateway
                           │
                           ▼
                ┌─────────────────────┐
                │ Spring Boot         │
                │                     │
                │ RequestLogFilter    │
                │        │            │
                │        ▼            │
                │ Request Wrapper     │
                │        │            │
                │        ▼            │
                │ Controller          │
                │        │            │
                │        ▼            │
                │ Service             │
                │        │            │
                │        ▼            │
                │ Response            │
                └────────┬────────────┘
                         │
                         ▼
                    RequestLog
                         │
                 ┌───────┴────────┐
                 │                │
                 ▼                ▼
              脱敏处理          Body限制
                 │                │
                 └───────┬────────┘
                         │
                         ▼
                    异步队列
                         │
             ┌───────────┼───────────┐
             │           │           │
             ▼           ▼           ▼
           MySQL      Elasticsearch  Loki
                         │
                         ▼
                  Actuator Endpoint
                         │
                         ▼
             /actuator/request-logs

32. 最终推荐方案

如果只是开发环境:

text 复制代码
Spring Boot
    +
OncePerRequestFilter
    +
ContentCachingRequestWrapper
    +
ContentCachingResponseWrapper

即可。

如果是生产环境:

text 复制代码
Spring Boot
    +
RequestLogFilter
    +
ContentCachingRequestWrapper
    +
ContentCachingResponseWrapper
    +
Body大小限制
    +
URL过滤
    +
Content-Type过滤
    +
敏感数据脱敏
    +
TraceId
    +
异步日志
    +
MySQL / Elasticsearch
    +
Actuator

33. 核心结论

整个方案可以总结成:

text 复制代码
                    Actuator
                       │
          ┌────────────┴────────────┐
          │                         │
          ▼                         ▼
       Metrics                 自定义Endpoint
          │                         │
          │                         ▼
          │                /actuator/request-logs
          │
          ▼
    HTTP请求指标


HTTP请求
    │
    ▼
RequestLogFilter
    │
    ├── Method
    ├── URI
    ├── QueryString
    ├── Request Body
    ├── Response Body
    ├── Status
    ├── Cost
    ├── Client IP
    ├── User ID
    └── TraceId
             │
             ▼
        脱敏 + 大小限制
             │
             ▼
          异步保存
             │
             ▼
       MySQL / ES / Loki

核心技术点只有两个:

java 复制代码
ContentCachingRequestWrapper

负责缓存 Request Body。

java 复制代码
ContentCachingResponseWrapper

负责缓存 Response Body。

然后通过:

java 复制代码
OncePerRequestFilter

统一采集请求信息。

而:

text 复制代码
Spring Boot Actuator

负责提供监控指标和自定义管理端点。

因此,不建议把"完整 HTTP 请求日志"理解成 Actuator 的功能,而应该理解成"Filter 采集 + Actuator 管理/暴露"。


34. 下一步完善建议

如果用于实际生产项目,建议继续完善以下能力:

  1. 完整可运行的 Spring Boot 3.x + JDK 17 示例
  2. MyBatis-Plus 持久化
  3. MySQL 建表 + Entity + Mapper + Service
  4. Request/Response JSON 自动格式化
  5. 密码、Token、手机号、身份证号自动脱敏
  6. Request/Response Body 最大长度限制
  7. 文件上传自动跳过
  8. 异常请求完整记录
  9. TraceId 自动生成和传递
  10. 用户 ID 自动获取
  11. URL 白名单/黑名单
  12. 异步写入,避免影响接口性能
  13. 自定义 /actuator/request-logs
  14. 按 URI、状态码、时间范围查询
  15. 日志自动清理/保留策略
  16. 高并发下的性能优化
  17. ELK / Loki 日志方案

对于正式生产系统,建议最终采用:

text 复制代码
HTTP
 ↓
RequestLogFilter
 ↓
采集请求/响应
 ↓
脱敏
 ↓
TraceId
 ↓
异步队列
 ↓
Elasticsearch / Loki
 ↓
Grafana / Kibana

而不是让每一次 HTTP 请求直接同步写 MySQL。

相关推荐
java1234_小锋1 小时前
MyBatis-Plus 3.5.15 已全面支持 Spring Boot 4.0 及 Jackson 3.0
java·spring boot·mybatis
xixingzhe21 小时前
spring boot项目接口访问慢问题解决方案
java·数据库·spring boot
MetaLite1 小时前
SpringBoot整合FastJson2数据脱敏-接口日志与失败降级
java·spring boot·后端
xixingzhe21 小时前
SpringBoot 接口缓存实现
spring boot·后端·缓存
摇滚侠1 小时前
《SpringBoot 3:入门与应用实战》第 13 章 整合 MyBatis 使用 MyBatis-Plus 阅读笔记 40
spring boot·笔记·mybatis
行百里er13 小时前
Gateway 上别硬塞 MVC:DeferredImportSelector 看菜下锅
spring boot·后端·开源
黑马程序员毕设14 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
xcl092515 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·spring boot·需求分析
wxwx_bscxy32215 小时前
基于springboot宠物领养系统的设计与实现
数据库·spring boot·后端·spring·宠物