Spring Boot拦截HTTP请求与设置请求头实战指南

发布时间:2026/9/14 22:15:02

Spring Boot拦截HTTP请求与设置请求头实战指南 1. Spring Boot拦截HTTP请求设置请求头的核心场景在Web开发中经常需要统一处理HTTP请求和响应。比如在微服务架构中我们可能需要在所有请求中添加认证头如JWT Token或者记录请求日志、修改响应内容。Spring Boot提供了多种方式来实现这种拦截需求其中最常见的是通过过滤器Filter和拦截器Interceptor。关键区别Filter是Servlet规范的一部分工作在更底层Interceptor是Spring MVC的组件可以访问Spring上下文。我最近在一个电商项目中就遇到了这样的需求需要在所有API请求中添加一个X-Request-ID头用于全链路追踪。经过对比几种方案最终选择了过滤器的方式实现。下面分享具体实现过程和踩过的坑。2. 实现HTTP请求拦截的三种核心方式2.1 使用Servlet Filter这是最基础的方式适合简单的请求/响应修改。创建一个实现javax.servlet.Filter接口的类public class CustomHeaderFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; HttpServletResponse httpResponse (HttpServletResponse) response; // 添加自定义请求头 httpResponse.setHeader(X-Custom-Header, value); // 继续过滤器链 chain.doFilter(httpRequest, httpResponse); } }注册过滤器有两种方式使用Component注解自动注册通过FilterRegistrationBean手动注册推荐可以控制顺序Configuration public class FilterConfig { Bean public FilterRegistrationBeanCustomHeaderFilter filterRegistrationBean() { FilterRegistrationBeanCustomHeaderFilter registration new FilterRegistrationBean(); registration.setFilter(new CustomHeaderFilter()); registration.addUrlPatterns(/*); registration.setOrder(1); // 设置过滤器顺序 return registration; } }2.2 使用Spring InterceptorInterceptor可以访问Spring上下文更适合需要依赖注入的场景。实现步骤创建拦截器类实现HandlerInterceptorpublic class CustomHeaderInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { response.setHeader(X-Interceptor-Header, interceptor-value); return true; } }注册拦截器Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new CustomHeaderInterceptor()) .addPathPatterns(/**); } }2.3 使用ControllerAdvice ResponseBodyAdvice对于只需要修改响应体的场景可以使用这个组合ControllerAdvice public class CustomHeaderAdvice implements ResponseBodyAdviceObject { Override public boolean supports(MethodParameter returnType, Class? extends HttpMessageConverter? converterType) { return true; } Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class? extends HttpMessageConverter? selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { response.getHeaders().add(X-Advice-Header, advice-value); return body; } }3. 实战实现全链路请求ID追踪下面通过一个完整示例演示如何在微服务中实现请求追踪。我们需要如果请求没有X-Request-ID头生成一个UUID将该ID添加到响应头在日志中记录这个ID3.1 创建RequestIdFilterpublic class RequestIdFilter implements Filter { private static final String REQUEST_ID_HEADER X-Request-ID; private static final Logger logger LoggerFactory.getLogger(RequestIdFilter.class); Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest (HttpServletRequest) request; HttpServletResponse httpResponse (HttpServletResponse) response; // 获取或生成请求ID String requestId httpRequest.getHeader(REQUEST_ID_HEADER); if (requestId null || requestId.isEmpty()) { requestId UUID.randomUUID().toString(); } // 添加到响应头 httpResponse.setHeader(REQUEST_ID_HEADER, requestId); // 使用MDC记录请求ID便于日志追踪 MDC.put(requestId, requestId); try { logger.info(Incoming request: {} {}, httpRequest.getMethod(), httpRequest.getRequestURI()); chain.doFilter(httpRequest, httpResponse); } finally { MDC.remove(requestId); } } }3.2 配置日志模式在application.properties中添加logging.pattern.console%d{yyyy-MM-dd HH:mm:ss} [%thread] [%X{requestId}] %-5level %logger{36} - %msg%n3.3 注册过滤器Configuration public class WebConfig { Bean public FilterRegistrationBeanRequestIdFilter requestIdFilter() { FilterRegistrationBeanRequestIdFilter registration new FilterRegistrationBean(); registration.setFilter(new RequestIdFilter()); registration.addUrlPatterns(/*); registration.setOrder(Ordered.HIGHEST_PRECEDENCE); // 最高优先级 return registration; } }4. 高级应用场景与优化4.1 性能优化避免频繁创建对象在过滤器中使用ThreadLocal缓存常用对象public class PerformanceFilter implements Filter { private static final ThreadLocalSimpleDateFormat dateFormatHolder ThreadLocal.withInitial(() - new SimpleDateFormat(yyyy-MM-dd HH:mm:ss)); Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // 使用缓存的对象 String formattedDate dateFormatHolder.get().format(new Date()); response.setHeader(X-Process-Time, formattedDate); chain.doFilter(request, response); } }4.2 安全头设置常见的安全头设置示例public class SecurityHeadersFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletResponse httpResponse (HttpServletResponse) response; // 防止点击劫持 httpResponse.setHeader(X-Frame-Options, DENY); // XSS保护 httpResponse.setHeader(X-XSS-Protection, 1; modeblock); // 禁止MIME类型嗅探 httpResponse.setHeader(X-Content-Type-Options, nosniff); // CSP策略 httpResponse.setHeader(Content-Security-Policy, default-src self); chain.doFilter(request, response); } }4.3 动态修改请求头有时我们需要在拦截器中修改请求头。由于HttpServletRequest的头部是只读的我们需要使用包装类public class HeaderModificationFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { chain.doFilter(new HttpServletRequestWrapper((HttpServletRequest) request) { Override public String getHeader(String name) { if (User-Agent.equalsIgnoreCase(name)) { return Modified-Agent; } return super.getHeader(name); } Override public EnumerationString getHeaders(String name) { if (User-Agent.equalsIgnoreCase(name)) { return Collections.enumeration(Arrays.asList(Modified-Agent)); } return super.getHeaders(name); } }, response); } }5. 常见问题与解决方案5.1 过滤器不生效的可能原因顺序问题过滤器可能被其他过滤器提前终止解决方案调整Order或setOrder()值URL模式不匹配确保addUrlPatterns()包含你的路径缺少组件扫描确保配置类在组件扫描路径下5.2 拦截器与过滤器的执行顺序典型请求处理流程客户端请求 - Servlet Filter Chain - DispatcherServlet - Interceptor preHandle - Controller - Interceptor postHandle - Interceptor afterCompletion - Servlet Filter Chain - 客户端响应5.3 性能监控实现示例public class MetricsFilter implements Filter { private static final String START_TIME_ATTR startTime; Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long startTime System.currentTimeMillis(); request.setAttribute(START_TIME_ATTR, startTime); chain.doFilter(request, response); long duration System.currentTimeMillis() - startTime; response.setHeader(X-Processing-Time, duration ms); } }5.4 跨域处理的最佳实践虽然可以在过滤器中处理CORS但推荐使用Spring的专用机制Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/api/**) .allowedOrigins(https://trusted.com) .allowedMethods(GET, POST) .allowedHeaders(*) .exposedHeaders(X-Custom-Header) .maxAge(3600); } }6. 测试策略6.1 单元测试过滤器public class CustomHeaderFilterTest { Test public void testHeaderAdded() throws Exception { MockHttpServletRequest request new MockHttpServletRequest(); MockHttpServletResponse response new MockHttpServletResponse(); MockFilterChain chain new MockFilterChain(); new CustomHeaderFilter().doFilter(request, response, chain); assertEquals(value, response.getHeader(X-Custom-Header)); } }6.2 集成测试SpringBootTest AutoConfigureMockMvc public class FilterIntegrationTest { Autowired private MockMvc mockMvc; Test public void testRequestIdHeader() throws Exception { mockMvc.perform(get(/api/test)) .andExpect(header().exists(X-Request-ID)); } }6.3 使用Postman测试发送请求并检查响应头测试不同场景不带请求头的请求带自定义请求头的请求测试安全头是否生效7. 性能考量与最佳实践过滤器链长度每个过滤器都会增加处理时间保持链尽可能短避免阻塞操作不要在过滤器中执行长时间阻塞操作线程安全确保过滤器是线程安全的资源清理在finally块中清理资源如MDC缓存策略对于频繁使用的值考虑使用缓存在最近的一个性能测试中我们发现每增加一个简单的过滤器平均响应时间增加约0.3ms在4核8G的测试环境。当过滤器数量超过10个时性能下降变得明显。因此建议合并相关功能的过滤器将不必要对所有请求生效的过滤器改为只匹配特定路径对于性能关键路径考虑使用更高效的实现方式8. Spring Boot 3.x的新特性在Spring Boot 3.x中过滤器注册有了更简洁的方式Configuration public class FilterConfig { Bean public ServletRegistrationBeanDispatcherServlet dispatcherServletRegistration() { return new ServletRegistrationBean(new DispatcherServlet(), /); } Bean public FilterRegistrationBeanCustomHeaderFilter customHeaderFilter() { return new FilterRegistrationBean(new CustomHeaderFilter()); } }另外Spring Boot 3.x对Servlet API的要求升级到了5.0需要注意兼容性问题。9. 实际项目经验分享在电商项目中实现全链路追踪时我们遇到了几个关键问题异步请求的请求ID传递解决方案使用TaskDecorator包装异步任务Configuration public class AsyncConfig implements AsyncConfigurer { Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor new ThreadPoolTaskExecutor(); executor.setTaskDecorator(new MDCTaskDecorator()); // 其他配置... return executor; } }网关层与微服务的ID传递在网关层生成请求ID通过Feign拦截器传递给下游服务public class FeignRequestInterceptor implements RequestInterceptor { Override public void apply(RequestTemplate template) { String requestId MDC.get(requestId); if (requestId ! null) { template.header(X-Request-ID, requestId); } } }日志系统的集成配置Logback/SLF4J使用MDC中的requestId在ELK等日志系统中建立基于requestId的关联10. 扩展思考更现代的替代方案虽然过滤器和拦截器仍然有效但在新项目中也可以考虑Spring Cloud Gateway过滤器适用于微服务架构的网关层Servlet 3.1的异步处理对于长时间运行的请求Reactive StackWebFlux提供的WebFilter机制Micrometer追踪与分布式追踪系统集成对于全新的Spring Boot 3.x项目WebFlux提供了一种更现代的替代方案Component public class CustomWebFilter implements WebFilter { Override public MonoVoid filter(ServerWebExchange exchange, WebFilterChain chain) { exchange.getResponse().getHeaders().add(X-Custom-Header, value); return chain.filter(exchange); } }这种响应式的方式在处理高并发请求时通常有更好的性能表现。
延伸阅读

更多相关文章

2026/9/10 5:06:10

Python包管理进阶:使用pip从Git仓库直接安装与配置指南

1. 为什么需要从Git仓库直接安装Python包? 在Python开发中,我们最熟悉的包安装方式无疑是 pip install package-name 。这个命令会从PyPI(Python Package Index)这个官方的软件仓库中,拉取对应名称的包及其依赖&…

2026/9/14 7:49:51

安卓模拟器安装Magisk:安全沙盒中实现系统级Root与模块测试

1. 项目概述:为什么要在模拟器里折腾Magisk?如果你和我一样,是个喜欢在安卓世界里“搞机”的玩家,那么对Magisk一定不陌生。它早已超越了单纯的Root工具,成为了一个强大的模块化框架,能让我们在不破坏系统完…

2026/9/13 9:40:59

百度网盘提取码智能获取:5秒破解资源锁定的终极指南

百度网盘提取码智能获取:5秒破解资源锁定的终极指南 【免费下载链接】baidupankey 在线查询网盘提取码(维护中 rm repo) 项目地址: https://gitcode.com/gh_mirrors/ba/baidupankey 还在为百度网盘加密资源而烦恼吗?每次打…

2026/9/14 22:10:38

Rufus:绿色U盘启动盘制作工具,5分钟把U盘变成可引导U盘

Rufus:绿色U盘启动盘制作工具,5分钟把U盘变成可引导U盘 【免费下载链接】rufus The Reliable USB Formatting Utility 项目地址: https://gitcode.com/GitHub_Trending/ru/rufus Rufus 是一个绿色单文件工具,插入U盘即可把它格式化成 …

2026/9/14 22:10:38

VisionPro手术导航:医疗MR的精度革命与临床落地

1. 项目概述:这不是一台“头显”,而是一台悬浮在视网膜上的手术导航仪 我第一次把VisionPro戴在头上时,手是悬空的——不是因为紧张,而是下意识想用手指去“推”眼前那块半透明的3D解剖图。它没动。但当我微微偏头,那颗…

2026/9/14 22:05:37

Python Flask/Django构建汽修数字化管理系统实践

1. 项目背景与核心价值汽车维修保养行业正经历从传统纸质工单向数字化管理的转型浪潮。作为从业十年的全栈开发者,我亲历过数十家汽修门店因管理系统落后导致的客户流失、库存混乱问题。这套基于Python Flask/Django框架的系统,正是为解决以下行业痛点而…

2026/9/14 2:17:50

拯救者Y7000黑屏故障排查与维修实战指南

1. 项目概述:一台黑屏的拯救者Y7000,到底卡在哪一步? 联想拯救者Y7000系列笔记本,从2018年第一代搭载i5-8300H开始,到后来的i7-9750H、i7-10750H、i5-11400H,再到2023年款的R7-7840HS,它始终是学…

2026/9/14 0:03:22

KCF目标跟踪算法与OTB工程实现:毕业设计实战解析

简介:这是一份基于KCF核相关滤波算法、融合尺度池与抗遮挡处理的目标检测跟踪MATLAB完整源码,主要面向计算机相关专业准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初学者。源码在OTB数据集上完成验证,能够…

2026/9/14 0:03:22

语音情感识别实战:Keras实现LSTM、CNN、SVM与MLP多模型对比

简介:面向语音情感识别入门与进阶开发者,这份基于Keras的项目源码完整实现了LSTM、CNN、SVM、MLP四种模型,兼容Python3.8与Keras/TensorFlow2环境。压缩包内含49个文件,大小约70.31MB,主体包括Python脚本、yaml/json配…

2026/9/14 11:59:31

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/14 13:53:59

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/14 11:22:57

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码