SpringBoot实现拦截Http请求并设置请求头

 更新时间:2026年01月29日 09:50:20   作者:你这个代码我看不懂  
这篇文章主要为大家详细介绍了如何使用SpringBoot实现拦截Http请求并设置请求头,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

ClientHttpRequestInterceptor拦截器

在Spring Boot中,你可以通过拦截RestTemplate请求并在发送前设置请求头,通常有以下两种方式实现:

1. 使用ClientHttpRequestInterceptor

通过自定义拦截器ClientHttpRequestInterceptor,在intercept方法中修改请求头,然后将拦截器添加到RestTemplate实例中。

步骤:

  • 创建拦截器类实现ClientHttpRequestInterceptor接口
  • intercept方法中添加或修改请求头
  • 将拦截器注册到RestTemplate

示例代码:

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Collections;

public class HeaderInterceptor implements ClientHttpRequestInterceptor {
    
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
                                      ClientHttpRequestExecution execution) throws IOException {
        // 添加请求头
        request.getHeaders().add("Authorization", "Bearer your-token");
        request.getHeaders().add("Custom-Header", "custom-value");
        
        return execution.execute(request, body);
    }
}

// 配置RestTemplate
@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setInterceptors(Collections.singletonList(new HeaderInterceptor()));
    return restTemplate;
}

2. 使用RestTemplateBuilder(推荐)

通过RestTemplateBuilder可以更方便地添加拦截器,支持链式调用。

示例代码:

import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {
    
    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .additionalInterceptors(new HeaderInterceptor())
                .build();
    }
}

3. 动态设置请求头(针对特定请求)

如果某些请求头需要动态设置(如从上下文获取token),可以在拦截器中加入逻辑:

public class DynamicHeaderInterceptor implements ClientHttpRequestInterceptor {
    
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, 
                                      ClientHttpRequestExecution execution) throws IOException {
        // 从安全上下文或其他来源动态获取值
        String token = SecurityContextHolder.getContext().getAuthentication().getCredentials().toString();
        request.getHeaders().add("Authorization", "Bearer " + token);
        
        return execution.execute(request, body);
    }
}

注意事项

  • 拦截器会应用于所有通过该RestTemplate发起的请求
  • 如果需要为不同请求设置不同请求头,可在拦截器中根据request.getURI()判断路径
  • 考虑使用ThreadLocal存储线程安全的上下文信息(如请求ID)

如果需要更细粒度的控制,可以考虑使用RestTemplateexchange()方法直接传入HttpEntity(包含头部信息),但这种方式需要在每次调用时显式设置。

统一拦截所有HTTP请求

要统一拦截所有HTTP请求(包括RestTemplate、WebClient、Feign等),可以通过以下几种方式实现:

1. 使用Spring的ClientHttpRequestInterceptor(仅适用于RestTemplate)

适用于所有通过RestTemplate发起的请求,但对其他客户端无效。

2. 使用Servlet Filter(最通用)

Filter可以拦截所有进入容器的HTTP请求,包括:

  • RestTemplate发起的请求
  • WebClient发起的请求
  • Feign客户端发起的请求
  • 任何其他HTTP客户端发起的请求

示例代码:

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
@Order(1) // 执行顺序
public class GlobalHttpFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                        FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        
        // 添加全局请求头
        if (httpRequest.getHeader("Authorization") == null) {
            // 这里可以设置默认认证头或其他通用头
        }
        
        // 记录请求日志
        System.out.println("Request URL: " + httpRequest.getRequestURL());
        System.out.println("Method: " + httpRequest.getMethod());
        
        chain.doFilter(request, response); // 继续执行过滤器链
    }
}

3. 使用AOP面向切面编程

通过AOP拦截所有HTTP客户端调用方法:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class HttpRequestAspect {

    @Around("execution(* org.springframework.web.client.RestTemplate.*(..)) || " +
            "execution(* org.springframework.web.reactive.function.client.WebClient.*(..))")
    public Object aroundHttpRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        
        // 在方法执行前添加请求头
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof HttpEntity) {
                HttpEntity<?> entity = (HttpEntity<?>) args[i];
                HttpHeaders headers = new HttpHeaders();
                headers.putAll(entity.getHeaders());
                headers.add("Global-Header", "common-value");
                
                // 替换为新的HttpEntity
                args[i] = new HttpEntity<>(entity.getBody(), headers);
            }
        }
        
        return joinPoint.proceed(args);
    }
}

4. 使用OkHttp的Interceptor(如果使用OkHttp作为底层客户端)

import okhttp3.Interceptor;
import okhttp3.Response;
import java.io.IOException;

public class GlobalOkHttpInterceptor implements Interceptor {
    @Override
    public Response intercept(Chain chain) throws IOException {
        return chain.proceed(chain.request().newBuilder()
                .addHeader("Authorization", "Bearer token")
                .addHeader("X-Request-ID", UUID.randomUUID().toString())
                .build());
    }
}

5. 推荐方案:组合使用

拦截方式适用范围优点缺点
Servlet Filter所有HTTP请求最通用,覆盖全面无法区分内部/外部请求
AOP方法级别拦截精确控制,可区分业务配置相对复杂
ClientHttpRequestInterceptor仅RestTemplate简单易用局限性大
OkHttp Interceptor使用OkHttp的客户端性能好需要统一HTTP客户端

最佳实践建议:

  • 使用Servlet Filter处理全局通用的请求头(如追踪ID、基础认证)
  • 使用AOP处理业务特定的拦截逻辑
  • 根据项目使用的HTTP客户端选择相应的拦截机制

根据你的需求,Servlet Filter通常是最合适的统一拦截方案。

手动拦截并设置(反射):

public void setRequestHeader(String key, String value) {
        if (StringUtils.isEmpty(key) || StringUtils.isEmpty(value)) {
            return;
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (null == attributes) {
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        Class<? extends HttpServletRequest> requestClass = request.getClass();
        try {
            // 反射获取request属性
            Field headerField = requestClass.getDeclaredField("headerMap");
            headerField.setAccessible(true);
            Map<String, String> headerMap = (Map<String, String>) headerField.get(request);
            headerMap.put(key, value);
        } catch (Exception e) {
            log.error("set header error: ", e);
        }
    }

ClientHttpRequestInterceptor 会在 每次 通过配置了该拦截器的 RestTemplate 实例发起 HTTP 调用之前执行。

工作原理

当你调用 RestTemplate 的任何方法(如 getForObject, postForEntity, exchange 等)时,Spring 会按以下顺序处理:

  • 你调用 restTemplate.getForObject(...)
  • Spring 开始构建实际的 HTTP 请求
  • 在执行网络调用之前,Spring 会遍历所有已注册的 ClientHttpRequestInterceptor
  • 按顺序调用每个拦截器的 intercept 方法
  • 在你的 intercept 方法中,你可以检查和修改请求(HttpRequest)和请求体(byte[] body
  • 所有拦截器执行完毕后,最终调用 execution.execute(request, body) 来真正地发送网络请求

关键特性

  • 每次调用都执行:无论这个 RestTemplate 实例被调用多少次,拦截器都会在每次请求前工作。
  • 适用于所有方法:它不区分 get, post, put, delete 等方法,对所有通过该 RestTemplate 发起的请求一视同仁。
  • 可设置多个拦截器:你可以为一个 RestTemplate 添加多个拦截器,它们会按照添加的顺序依次执行。

示例场景验证

假设你有以下配置和代码:

// 1. 定义一个打印日志的拦截器
public class LoggingInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        System.out.println("【拦截器执行】准备发送请求至: " + request.getURI());
        // ... 可以在这里添加请求头
        return execution.execute(request, body);
    }
}

// 2. 将拦截器添加到 RestTemplate
@Bean
public RestTemplate restTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.setInterceptors(Collections.singletonList(new LoggingInterceptor()));
    return restTemplate;
}

// 3. 在服务中多次使用 RestTemplate
@Service
public class MyService {

    @Autowired
    private RestTemplate restTemplate;

    public void fetchData() {
        // 第一次调用
        String result1 = restTemplate.getForObject("https://api.example.com/data/1", String.class);
        
        // 第二次调用
        String result2 = restTemplate.getForObject("https://api.example.com/data/2", String.class);
    }
}

当你调用 myService.fetchData() 时,控制台会输出:

【拦截器执行】准备发送请求至: https://api.example.com/data/1
【拦截器执行】准备发送请求至: https://api.example.com/data/2

这清楚地证明了拦截器为每次请求都执行了一次。

总结

你可以放心地依赖 ClientHttpRequestInterceptor 来执行诸如添加认证令牌、设置公共请求头、记录请求日志、重试逻辑等需要在每个请求发出前完成的统一操作。它的设计初衷就是为此类场景服务的。

Attribute和Header

  • Attribute(属性)服务端内部的“便签”,用于在一次请求的生命周期内,在服务器内部的各个组件(如Controller、Service、Interceptor、Filter、View等)之间传递数据。客户端(如浏览器)完全不知道它的存在。
  • Header(头信息)客户端和服务器之间正式通信协议(HTTP)的一部分,用于传递元数据(如内容类型、认证信息、缓存控制等)。它对客户端是可见的,并且通常会影响请求/响应的处理方式。

下面是一个详细的对比表格,帮助你更清晰地理解:

特性Attribute(属性)Header(头信息)
作用域服务器端的一次请求生命周期内(Request Scope)**HTTP协议本身,在客户端和服务器之间传输
可见性仅服务器内部可见(如Filter, Interceptor, Controller, Service, JSP/Thymeleaf等)客户端和服务器都可见,可通过浏览器开发者工具或抓包工具查看
用途在服务器处理请求的过程中,在不同组件间传递数据。例如:
- Filter校验用户后,将用户信息存入attribute供Controller使用
- Interceptor计算耗时后,将耗时结果存入attribute
传递HTTP协议的元数据。例如:
- Content-Type: 声明请求体/响应体的格式(如application/json)
- Authorization: 传递认证凭证(如Bearer token)
- User-Agent: 声明客户端类型
- Custom-Header: 自定义业务头(如X-Request-ID用于全链路追踪)
生命周期从请求进入服务器开始,到服务器返回响应结束。请求结束即销毁。请求头(Request Header) 随请求从客户端发往服务器。
响应头(Response Header) 随响应从服务器发往客户端。
数据类型可以是任何Java对象(Object)只能是字符串(String)或字符串数组(String[])
操作方式 (Java)request.setAttribute("key", value);
Object value = request.getAttribute("key");
获取请求头:
String value = request.getHeader("Header-Name");
设置响应头:
response.setHeader("Header-Name", "value");
response.addHeader("Header-Name", "value");

类比帮助理解

你可以把它们想象成寄送一个实体包裹:

  • Header 就像是包裹外面的快递单。上面写明了收件人地址、寄件人信息、包裹类型(易碎品)、是否需要代收款等。快递员和收发货双方都能看到这个单子,并根据上面的信息来处理包裹。
  • Attribute 就像是包裹里面的一张内部纸条,是发货人写给仓库分拣员的,比如“这是VIP客户的加急订单,优先处理”。只有打开包裹的内部人员(服务器)才能看到这张纸条,收货人(客户端)根本不知道它的存在。

代码示例

1. 操作 Header (在Servlet Filter或Controller中)

// 从客户端发来的请求中获取头信息
String authHeader = httpRequest.getHeader("Authorization");
String userAgent = httpRequest.getHeader("User-Agent");

// 向客户端发送响应时设置头信息
httpResponse.setHeader("Content-Type", "application/json");
httpResponse.addHeader("X-Custom-Header", "MyValue");

2. 操作 Attribute (在Filter, Interceptor, Controller中)

// 在Filter中设置属性
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    // 认证成功后,将用户信息存入attribute
    User user = authenticateUser(httpRequest);
    httpRequest.setAttribute("currentUser", user); // 存入任何对象
    chain.doFilter(request, response);
}

// 在Controller中获取和使用属性
@GetMapping("/api/profile")
public ResponseEntity getUserProfile(HttpServletRequest request) {
    // 从attribute中取出之前存入的对象
    User currentUser = (User) request.getAttribute("currentUser");
    // ... 使用user对象处理业务
    return ResponseEntity.ok(currentUser.getProfile());
}

总结

记住这个最简单的原则:

  • 需要让客户端知晓或受其影响的信息,用 Header(如认证、缓存、内容协商)。
  • 只在服务器内部处理过程中需要临时携带的数据,用 Attribute(如用户身份、计算中间结果、页面渲染数据)。

到此这篇关于SpringBoot实现拦截Http请求并设置请求头的文章就介绍到这了,更多相关SpringBoot拦截Http请求内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中获取webapp路径问题详解

    Java中获取webapp路径问题详解

    这篇文章主要介绍了Java中获取webapp路径问题详解,WebApp是指基于Web的 系统和 应用,其作用是向广大的最终用户发布一组复杂的内容和功能,本文详解了关于获取路径时候可能出现的问题,需要的朋友可以参考下
    2023-07-07
  • SpringBoot启动时运行特定代码的多种方式小结

    SpringBoot启动时运行特定代码的多种方式小结

    SpringBoot提供了多种方式在应用程序启动时运行特定的代码,包括CommandLineRunner、ApplicationRunner、@PostConstruct、InitializingBean、事件机制和自定义注解等,下面就来具体介绍一下
    2025-01-01
  • spring boot集成mongodb的增删改查的示例代码

    spring boot集成mongodb的增删改查的示例代码

    这篇文章主要介绍了spring boot集成mongodb的增删改查的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • SpringSecurity多认证器配置多模式登录自定义认证器方式

    SpringSecurity多认证器配置多模式登录自定义认证器方式

    这篇文章主要介绍了SpringSecurity多认证器配置多模式登录自定义认证器方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2025-04-04
  • java实现的冒泡排序算法示例

    java实现的冒泡排序算法示例

    这篇文章主要介绍了java实现的冒泡排序算法,结合实例形式分析了冒泡排序算法的具体操作步骤与实现技巧,需要的朋友可以参考下
    2017-01-01
  • Springboot过滤器禁止ip频繁访问功能实现

    Springboot过滤器禁止ip频繁访问功能实现

    这篇文章主要介绍了Springboot过滤器禁止ip频繁访问功能实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • idea常用配置之注释快捷键方式

    idea常用配置之注释快捷键方式

    这篇文章主要介绍了idea常用配置之注释快捷键方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • Java Lambda表达式实例解析原理

    Java Lambda表达式实例解析原理

    日常开发中,我们很多时候需要用到Java 8的Lambda表达式,它允许把函数作为一个方法的参数,让我们的代码更优雅、更简洁。所以整理了一波工作中常用的Lambda表达式。看完一定会有帮助的
    2023-03-03
  • Object类toString()和equals()方法使用解析

    Object类toString()和equals()方法使用解析

    这篇文章主要介绍了Object类toString()和equals()方法使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • Spring Security中用JWT退出登录时遇到的坑

    Spring Security中用JWT退出登录时遇到的坑

    使用了JWT后,每次请求都要携带 Bearer Token 并且被专门的过滤器拦截解析之后才能将用户认证信息保存到 SecurityContext 中去,接下来通过本文给大家介绍Spring Security中用JWT退出登录时遇到的坑,感兴趣的朋友一起看看吧
    2021-10-10

最新评论