@RequestHeader注解

第一种方式,这个很简单,在方法参数列表里上加注解@RequestHeader就行。

  1. @PostMapping(value = "/getStuDetail")
  2. public ReturnInfo getStudentDetail(@RequestBody Map map,@RequestHeader(name = "id") String id);

RequestInterceptor接口

第二种方法,实现RequestInterceptor接口,重写apply函数。

  1. @Configuration
  2. public class FeignRequestInterceptor implements RequestInterceptor {
  3. @Override
  4. public void apply(RequestTemplate template) {
  5. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  6. HttpServletRequest request = attributes.getRequest();
  7. Enumeration<String> headerNames = request.getHeaderNames();
  8. if (headerNames != null) {
  9. while (headerNames.hasMoreElements()) {
  10. String name = headerNames.nextElement();
  11. String values = request.getHeader(name);
  12. // 调用 template.header设置header信息
  13. template.header(name, values);
  14. }
  15. }
  16. }
  17. }
  18. @Component
  19. @FeignClient(value = "xxxxxxxxx",configuration = FeignRequestInterceptor.class)
  20. public interface FeignProvider {
  21. }

在apply调用template.header设置header信息即可,然后发起feign请求的Provider设置configuration = FeignRequestInterceptor.class即可。

正确使用多个FeignRequestInterceptor

在FeignRequestInterceptor上加@Configuration这种方式,会影响所有的Feign请求。
如果有多个RequestInterceptor实现类并加上了@configuration,不管configuration参数指定与否,
所有的Feign请求会循环走完所有RequestInterceptor的apply函数。

这个时候你想要每个不同的FeignProvider走指定的RequestInterceptor的apply函数怎么办呢?
那就是在每个FeignRequestInterceptor上不要添加@Configuration以及@Component注解,什么注解都不要加,然后在每个单独的@FeignClient去指定不同的FeignRequestInterceptor。

FeignRequestInterceptor特殊的使用方式

当你想要多FeignRequestInterceptor时,又想要用@Configuration或者@Component注入一些Bean到FeignRequestInterceptor中怎么办呢?
我就遇到了此种情形,我的FeignRequestInterceptor需要使用到RedisTemplate对象来操作Redis,但是如果你加@Configuration声明为组件,则多RequestInterceptor时会乱套。
如果你不加@Configuration声明为组件,则你无法注入RedisTemplate。
这个时候可以绕过这个接口。下面是操作方法。

  1. import feign.RequestInterceptor;
  2. // 接口继承feign的RequestInterceptor
  3. public class ApiConfiguration implements RequestInterceptor {
  4. // 内部包含一个自定义的requestInterceptor
  5. private RedisRequestInterceptor requestInterceptor;
  6. public ApiConfiguration(RedisRequestInterceptor requestInterceptor) {
  7. this.requestInterceptor = requestInterceptor;
  8. }
  9. @Override
  10. public void apply(RequestTemplate template) {
  11. requestInterceptor.apply(template);
  12. }
  13. }
  14. // 自己模仿feign的RequestInterceptor定义一个ApiRequestInterceptor
  15. public interface ApiRequestInterceptor {
  16. /**
  17. * 自定义的feign 请求拦截
  18. *
  19. * @param template
  20. */
  21. void apply(RequestTemplate template);
  22. }
  23. // 操作redis的请求拦截器
  24. @Configuration
  25. public class RedisRequestInterceptor implements ApiRequestInterceptor {
  26. private final RedisTemplate<String, String> redisTemplate;
  27. public RedisRequestInterceptor(RedisTemplate<String, String> redisTemplate) {
  28. this.redisTemplate = redisTemplate;
  29. }
  30. @Override
  31. public void apply(RequestTemplate template) {
  32. // 从redis中取header, 只是一个示例。
  33. String header = redisTemplate.opsForValue().get("header");
  34. // 写到header中
  35. template.header("header", header);
  36. }
  37. }
  38. @FeignClient(name = Const.SERVICE_NAME, configuration = {ApiConfiguration.class})
  39. @Primary
  40. public interface ServiceProvider {
  41. }

ServiceProvider指定的ApiConfiguration没有加任何注解,内部定义了一个RedisRequestInterceptor对象。
然后真正的RedisRequestInterceptor上加上@Configuration注解并实现ApiRequestInterceptor接口。
这样feign运行时就会找到RedisRequestInterceptor这个bean并运行。