如何在Spring MVC中记录HTTP请求头及其他相关数据?
嗨,我来给你几个实用的方案,帮你在Spring MVC的GET请求日志里带上HTTP请求头和其他请求数据~
方案1:用HandlerInterceptor全局统一处理(推荐)
这个方法不用修改每个控制器方法,能全局给所有请求的日志自动加上请求头信息,非常省心。
步骤1:自定义请求日志拦截器
创建一个实现HandlerInterceptor的类,在请求进入控制器前把需要的请求头/请求数据放到**MDC(映射诊断上下文)**里——MDC是Logback的特性,能让你在日志模板里引用这些变量:
public class RequestLoggingInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 把需要的请求信息存入MDC,按需添加(注意敏感信息要脱敏!比如Authorization只存前几位) MDC.put("userAgent", request.getHeader("User-Agent")); MDC.put("requestUri", request.getRequestURI()); MDC.put("remoteIp", request.getRemoteAddr()); // 如果要记录其他请求头,比如Accept-Language,直接用request.getHeader("Accept-Language") return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // 必须清除MDC!因为Web容器的线程是复用的,不清除会导致后续请求拿到旧数据 MDC.clear(); } }
步骤2:把拦截器注册到Spring MVC
用Java配置把上面的拦截器加进去:
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestLoggingInterceptor()); } }
步骤3:修改Logback的日志模板
在你的<pattern>里加入MDC变量,用%X{变量名}的格式:
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - IP:%X{remoteIp}, UA:%X{userAgent}, URI:%X{requestUri} - %msg%n</pattern>
这样你原来的LOG.info("user successfully validated")就会自动带上这些请求信息,输出类似:
14:35:22.123 [http-nio-8080-exec-1] INFO com.example.BookmarkController - IP:127.0.0.1, UA:Mozilla/5.0..., URI:/users/john/bookmarks - user successfully validated
方案2:在控制器方法中直接获取并记录(适合局部需求)
如果只需要在特定的GET方法里记录请求头,不想全局处理,可以直接在方法参数里用@RequestHeader或者HttpServletRequest拿到数据,然后写到日志里:
@RequestMapping(method = RequestMethod.GET) Collection<Bookmark> readBookmarks( @PathVariable String userId, @RequestHeader("User-Agent") String userAgent, HttpServletRequest request ) { this.validateUser(userId); // 直接把需要的信息拼到日志里 LOG.info("user successfully validated | IP: {}, UA: {}, URI: {}", request.getRemoteAddr(), userAgent, request.getRequestURI()); return this.bookmarkRepository.findByAccountUsername(userId); }
这个方法灵活,但缺点是每个需要的方法都要加参数和日志代码,重复劳动比较多。
方案3:用Spring自带的CommonsRequestLoggingFilter
Spring提供了现成的请求日志过滤器,配置一下就能自动记录请求头、客户端信息等,适合快速实现全局请求日志:
步骤1:配置过滤器
@Configuration public class LoggingFilterConfig { @Bean public CommonsRequestLoggingFilter requestLoggingFilter() { CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter(); filter.setIncludeHeaders(true); // 开启请求头记录 filter.setIncludeClientInfo(true); // 记录客户端IP、主机名 filter.setIncludeQueryString(true); // 记录URL查询参数 filter.setIncludePayload(false); // GET请求一般没有请求体,设为false filter.setBeforeMessagePrefix("[REQUEST] "); // 日志前缀,方便识别 return filter; } }
步骤2:调整Logback日志级别
这个过滤器默认用DEBUG级别输出日志,所以需要在Logback里把它的日志级别打开:
<logger name="org.springframework.web.filter.CommonsRequestLoggingFilter" level="DEBUG"/>
之后它会自动打印类似这样的日志:
14:40:11.456 [http-nio-8080-exec-2] DEBUG o.s.w.f.CommonsRequestLoggingFilter - [REQUEST] Before request [GET /users/john/bookmarks, client=127.0.0.1, headers=[User-Agent:"Mozilla/5.0...", Accept:"application/json"]]
不过这个方案的日志格式比较固定,如果需要自定义格式,不如方案1灵活。
注意事项
- 敏感信息脱敏:比如
Authorization头里的token,不要直接完整记录,只存前几位或者用星号替换中间部分,避免泄露敏感数据。 - MDC清理:方案1里一定要在
afterCompletion里清除MDC,否则线程复用会导致日志混乱。 - 性能考虑:如果是高并发场景,全局日志要注意不要记录太多冗余数据,避免影响性能。
内容的提问来源于stack exchange,提问作者Phate
相关产品推荐
相关产品推荐

