OpenFeign调用微服务使用RequestInterceptor或@RequestHeader传递http请求头信息

文章介绍了在基于SpringCloudOpenFeign的微服务架构中,如何在调用Restful接口时传递请求头信息。第一种方法是使用RequestInterceptor接口,在调用前设置请求头;第二种方法是通过@RequestHeader注解直接在接口方法参数中指定请求头。两种方式都在实际代码示例中得到了详细解释。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

记录:391

场景:基于Spring Cloud OpenFeign调用微服务Restful接口时,请求头从A服务传递到B服务,可以使用RequestInterceptor接口或者@RequestHeader注解传递请求头信息。

版本:JDK 1.8,SpringBoot 2.6.3,springCloud 2021.0.1

1.使用RequestInterceptor传递请求头信息

1.1关于RequestInterceptor

RequestInterceptor是一个接口,全路径:feign.RequestInterceptor。

RequestInterceptor本质上就是一个拦截器,拦截时机是在OpenFeign调用Restful接口前拦截,因此可以设置请求信息。

使用RequestInterceptor,需实现它的apply(RequestTemplate var1)。换句话说,就是在apply方法中向RequestTemplate对象中注入请求头,

1.2实现RequestInterceptor接口

(1)代码

@Slf4j
@Configuration
public class FeignConfiguration implements RequestInterceptor {
  @Override
  public void apply(RequestTemplate requestTemplate) {
    // 1.从前端过来的请求头取信息
    RequestAttributes reqAttributes = RequestContextHolder.currentRequestAttributes();
    HttpServletRequest request = ((ServletRequestAttributes) reqAttributes).getRequest();
    String cityCode = request.getHeader("cityCode");
    requestTemplate.header("cityCode", cityCode);
    // 2.设置自定义请求头信息
    requestTemplate.header("cityNo", "0571");
  }
}

(2)解析

feign.RequestTemplate,feign的请求模板类,包括请求相关信息。

org.springframework.web.context.request.RequestContextHolder,取请求头工具类。

org.springframework.web.context.request.RequestAttributes,包含请求属性信息,是接口,需转换为实现类:org.springframework.web.context.request.ServletRequestAttributes。再取值。

1.3在OpenFeign接口应用RequestInterceptor

在OpenFeign接口应用RequestInterceptor,也就是引入RequestInterceptor接口实现类FeignConfiguration。

(1)代码

@FeignClient(contextId = "cityFeignService",
        value = "hub-example-301-nacos",
        fallbackFactory = CityFeignServiceFallbackFactory.class,
        configuration = {FeignConfiguration.class})
public interface CityFeignService {
    @PostMapping("/hub-301-nacos/hub/example/city/queryCityByCityId")
    ResultObj<CityDTO> queryCityByCityId(String cityId);
}

(2)解析

@FeignClient,feign客户端标识注解。

contextId,指定接口唯一标识。

fallbackFactory,指定接口回调函数。

configuration = {FeignConfiguration.class},就是执行feign接口调用时的配置信息,本例就是拦截请求头并设置请求头信息。

value = "hub-example-301-nacos",提供Restful接口的微服务名称,必须已经注册,本例使用Nacos注册。

1.4微服提供的Restful接口

(1)代码

@RestController
@RequestMapping("/hub/example/city")
@RefreshScope
@Slf4j
public class CityController {
    @Autowired
    private HttpServletRequest request;
    @PostMapping("/queryCityByCityId")
    public ResultObj<CityDTO> queryCityByCityId(String cityId) {
        log.info("cityCode = " + request.getHeader("cityCode"));
        log.info("cityNo = " + request.getHeader("cityNo"));
        CityDTO cityDTO = new CityDTO();
        cityDTO.setCityId(cityId != null ? Long.parseLong(cityId) : 1L);
        cityDTO.setCityName("杭州");
        cityDTO.setUpdateTime(new Date());
        return ResultObj.data(200, cityDTO, "执行成功");
    }
}

(2)解析

微服务提供的Restful接口和普通接口一致,无需改动。

注入javax.servlet.http.HttpServletRequest,是为了取出请求头信息做验证。

2.使用@RequestHeader传递请求头信息

2.1关于@RequestHeader

注解RequestHeader全路径:org.springframework.web.bind.annotation.RequestHeader。

注解RequestHeader,由Spring框架做拦截和配置。

2.2在OpenFeign接口应用@RequestHeader

在OpenFeign接口应用@RequestHeader,是把注解作用在OpenFeign接口方法参数上。

(1)代码

@FeignClient(contextId = "cityFeignService",
        value = "hub-example-301-nacos",
        fallbackFactory = CityFeignServiceFallbackFactory.class,
        configuration = {FeignConfiguration.class})
public interface CityFeignService {
    @PostMapping("/hub-301-nacos/hub/example/city/queryCityByCityName")
    ResultObj<CityDTO> queryCityByCityName(@RequestParam("cityName") String cityName, 
                                      @RequestHeader MultiValueMap<String, String> headers);
}

(2)解析

@RequestHeader,在方法上加上@RequestHead标记此参数是请求头信息。

MultiValueMap<String, String> headers,请求头传入的数据类型。

(3)注意

当使用@RequestHeader注解时,OpenFeign方法的其它参数必须使用@RequestParam指定参数名称,否则微服务会接收不到值。

@RequestParam("cityName") String cityName,双引号中的cityName必须和要被调用的Restful接口形参名称一致。

2.3调用OpenFeign接口

使用@RequestHeader传递参数时,需在调用OpenFeign接口前置手动组装参数MultiValueMap类型参数。

(1)代码

@Service
public class CityServiceImpl implements CityService {
  @Autowired
  private CityFeignService cityFeignService;
  @Override
  public ResultObj<CityDTO> queryCityByCityName(String cityName) {
    // 传入请求头
    MultiValueMap<String, String> headers = new HttpHeaders();
    headers.add("cityNo", "0571");
    return cityFeignService.queryCityByCityName(cityName, headers);
  }
}

(2)解析

一般是在Service服务层注入OpenFeign接口,在调用接口方法前先组装参数。

2.4微服提供的Restful接口

(1)代码

@RestController
@RequestMapping("/hub/example/city")
@RefreshScope
@Slf4j
public class CityController {
  @Autowired
  private HttpServletRequest request;
  @PostMapping("/queryCityByCityName")
  public ResultObj<CityDTO> queryCityByCityName(String cityName) {
    log.info("cityNo = " + request.getHeader("cityNo"));
    log.info("cityName = " + cityName);
    CityDTO cityDTO = new CityDTO();
    cityDTO.setCityId(1L);
    cityDTO.setCityName(cityName);
    cityDTO.setUpdateTime(new Date());
    log.info("cityDTO: " + cityDTO.toString());
    return ResultObj.data(200, cityDTO, "执行成功");
  }
}

(2)解析

微服务提供的Restful接口和普通接口一致,无需改动。

注入javax.servlet.http.HttpServletRequest,是为了取出请求头信息做验证。

3.几个类

类全路径:

java.util.Map。
org.springframework.util.MultiValueMap。
org.springframework.http.HttpHeaders。

继承关系:

public interface Map<K,V>。
public interface MultiValueMap<K, V> extends Map<K, List<V>>。
public class HttpHeaders implements MultiValueMap<String, String>, Serializable。

以上,感谢。

2023年3月24日

### 使用Feign客户端传递自定义HTTP请求头微服务架构中,当使用Feign作为Web Service客户端时,可以通过多种方式向远程服务发送带有特定头部信息HTTP请求。一种常见做法是在发起请求前利用拦截器机制动态地附加这些头部字段。 对于希望每次调用`MyFeignClient.getSomeData()`方法时都附带固定的header名称与值的情况,可以构建一个实现了`RequestInterceptor`接口的类——例如命名为`HeaderInterceptor`,在这个类里重写其唯一的抽象方法`apply(RequestTemplate template)`,并通过设置模板对象上的headers属性完成对欲添加项的操作[^1]: ```java import feign.RequestInterceptor; import feign.RequestTemplate; public class HeaderInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { template.header("headerName", "headerValue"); } } ``` 为了让上述逻辑生效,还需要确保此拦截器已被注册至应用程序上下文中;通常可以在启动类者其他配置组件内通过Java Config形式注入该bean实例即可。 另外,在实际业务场景下可能更倾向于依据当前环境变量是其他运行时期条件灵活决定要追加的具体键值对组合,则此时应当考虑借助于Spring框架所提供的依赖注入特性来简化此类操作。比如下面的例子展示了如何基于`@ConfigurationProperties`注解读取外部化配置文件里的参数并将其应用到待发送的数据包之中[^2]: ```yaml # application.yml or equivalent configuration file custom.headers: header-name: custom-value ``` ```java @Configuration @EnableConfigurationProperties(CustomHeaders.class) public class FeignConfig { private final CustomHeaders headers; public FeignConfig(CustomHeaders headers){ this.headers=headers; } @Bean public RequestInterceptor requestInterceptor() { return new RequestInterceptor() { @Override public void apply(RequestTemplate template) { Map<String, String> map = headers.asMap(); for (String key : map.keySet()) { template.header(key,map.get(key)); } } }; } } @Component @Data // Lombok annotation to generate getters and setters automatically. @ConfigurationProperties(prefix="custom.headers") class CustomHeaders extends HashMap<String,String>{}; ``` 除了全局性的解决方案外,针对单次API交互而言也可以直接采用`@RequestHeader`标注形参的方式来显式指明所需携带的内容。这使得开发者能够更加直观地控制每一次具体的RPC行为,并且保持良好的代码可读性和维护性[^3]。 #### 示例:结合`@RequestHeader`实现局部范围内的请求头定制 假设存在如下所示的服务消费端接口定义: ```java package com.example.demo.clients; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; @FeignClient(name = "example-service-client", url = "${service.url}") public interface ExampleServiceClient { @GetMapping("/api/data") ResponseEntity<DataResponseDTO> getData(@RequestHeader(value = "Custom-Header") String customHeaderValue); } ``` 这里的关键在于`getData`函数签名部分所使用的`@RequestHeader`修饰符及其后面的表达式,它表明每当有人尝试执行这个动作时都需要额外提供一个名为`Custom-Header`的字符串类型的输入参数用于填充即将发出的消息体之外的部分[^4]。 最后值得注意的是,在某些特殊场合下(如涉及跨域资源共享CORS策略、安全认证token传播等问题),可能会遇到即使按照常规手段设置了相应条目却仍然无法正常抵达目的地的现象。这时就需要深入探究整个网络传输路径上各个节点的行为模式,特别是像Zuul这样的路由代理层是否会对接收到的信息做进一步处理而导致原始意图失效的情形发生[^5]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值