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

发布时间:2026/11/13 11:18:58

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/11/12 4:57:12

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

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

2026/11/2 17:35:31

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

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

2026/11/12 18:12:03

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

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

2026/11/13 11:14:05

南充市电工证怎么报名 全国通用证件怎么考全攻略

南充市电工证怎么报名 全国通用证件怎么考全攻略 工地太忙根本没时间复习考试,这是很多一线施工人员的真实写照。尤其是在南充市这样的建筑工地集中地,电工证不仅是上岗的“通行证”,更是职业发展的“敲门砖”。但很多人因为工作太忙,根本抽不出时间去复…

2026/11/13 11:14:05

广汉附近考电工证丢了怎么补办 上岗必备的解决办法

广汉附近考电工证丢了怎么补办 上岗必备的解决办法 之前考的证在外省能不能转过来?这可能是很多在广汉附近准备考电工证或者已经持有电工证的人最关心的问题。特别是在三门峡这样的地区,很多在职建筑工人在换城市、换工作后,常常会遇到证书无法异地使用的…

2026/11/13 11:14:05

没有电工证操作违规吗官方报名入口全解析

没有电工证操作违规吗官方报名入口全解析 你有没有遇到过这种情况:刚找到一份电工相关的工作,却被告知必须持有电工证才能上岗?这种情况在建筑、电力、制造业等行业非常常见。特别是像郑州金水区这样的劳务市场,对特种作业人员的要求越来越严格,…

2026/11/13 11:14:05

大专电工证怎么考 怎么报名才能快速上岗

大专电工证怎么考 怎么报名才能快速上岗 你是不是正盯着招聘网站上的电工岗位,却发现“持有特种作业操作证”是硬性门槛?别急,这期内容讲的就是【大专电工证怎么考】,还有怎么报名、考试流程、岗位职责,全都给你安排得明明白白。…

2026/11/13 11:14:05

电工证是去哪里报名的官方报名入口在哪 考过不白交钱有诀窍

电工证是去哪里报名的官方报名入口在哪 考过不白交钱有诀窍 怕考不过白交培训费?你不是一个人!去年有300多人在信阳浉河区报名电工证,结果因为没找对官方报名入口,要么被坑钱,要么考了两次都没过。电工证是去哪里报名的?答案其实就在官方报名入口,…

2026/11/13 11:09:04

工地太忙没时间复习?个人电工证考试流程保姆级教程全公开

工地太忙没时间复习?个人电工证考试流程保姆级教程全公开 工地太忙根本没时间复习考试,这是很多一线电工的真实写照。面对繁重的工期和高强度的工作节奏,很多人连抽空准备考试都成了奢望。但现实是,没有电工证,就无法合法上岗作业。那么问题来了,…

2026/11/12 20:35:13

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/13 0:01:06

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了

办上海高压电工证良心建议:别被中介坑了,自己看这篇就够了 你是不是也像我一样,第一次听说“高压电工证”这个名词,就感觉一头雾水?其实很多人都跟我一样,不知道去哪报名、怕被中介坑,结果花了冤枉钱还考不上。今天我就从一个在商丘培训过的学员角度,…

2026/11/13 0:01:06

黎里考电工证在哪里值不值得考

黎里考电工证在哪里值不值得考 之前考的证在外省能不能转过来?这是很多在外地工作、准备回老家发展的朋友最关心的问题。特别是在黎里地区,很多从事电力相关工作的朋友,都面临这样一个难题: 外省的电工证能否在本地使用?值不值得考?…

2026/11/13 0:01:06

毕节哪里考电工证 怎么报名学历不高也能上手

毕节哪里考电工证 怎么报名学历不高也能上手 你是不是也和我一样,学历不高,想着考个电工证,但又担心自己条件不够,怕报不上名?其实不然,只要符合条件,学历不高也能考电工证。今天就来聊聊【毕节哪里考电工证】这个问题,还有怎么报名,让你一步到位不…

2026/11/12 22:10:13

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/12 9:51:42

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

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

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

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