广告位联系
返回顶部
分享到

FeignClient如何共享Header及踩坑过程记录

java 来源:互联网 作者:秩名 发布时间:2022-03-04 19:17:20 人浏览
摘要

FeignClient共享Header及踩坑 问题 我们在调用feign的情况下,经常需要用到客户端所持有的header比如说auth-token,我们需要将这些header传递下去 思路 使用拦截器,在客户端拦截feign的请求,

FeignClient共享Header及踩坑

问题

我们在调用feign的情况下,经常需要用到客户端所持有的header比如说auth-token,我们需要将这些header传递下去

思路

使用拦截器,在客户端拦截feign的请求,并把所需要的header传递下去

代码:

定义拦截器

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

@Configuration

public class FeignInterceptor implements RequestInterceptor {

    @Override

    public void apply(RequestTemplate requestTemplate) {

        Map<String,String> headers = getHeaders(getHttpServletRequest());

        for(String headerName : headers.keySet()){

            requestTemplate.header(headerName, getHeaders(getHttpServletRequest()).get(headerName));

        }

    }

    private HttpServletRequest getHttpServletRequest() {

        try {

            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();

        } catch (Exception e) {

            e.printStackTrace();

            return null;

        }

    }

    private Map<String, String> getHeaders(HttpServletRequest request) {

        Map<String, String> map = new LinkedHashMap<>();

        Enumeration<String> enumeration = request.getHeaderNames();

        while (enumeration.hasMoreElements()) {

            String key = enumeration.nextElement();

            if(needThisHeader(key)){

               String value = request.getHeader(key);

               map.put(key, value);

            }

        }

        return map;

    }

  private boolean needThisHeader(String headerName){

     //todo:这里写你的逻辑,哪些header需要传递,千万不能把所有的header传下去

      return true;

  }

}

将拦截器注入到Spring

1

2

3

4

5

6

7

8

9

10

11

12

@Configuration

public class FeignSupportConfig {

    /**

     * feign请求拦截器

     *

     * @return

     */

    @Bean

    public RequestInterceptor requestInterceptor(){

        return new FeignInterceptor();

    }

}

说说坑吧

一定不能把所有的header都往下传,这样很可能会导致在调用feign的时候,请求类型混乱,应该需要哪些header就穿哪些header

Feign设置Header头部

今天尝试用feign去调用其他部门提供的一个HTTP接口,该接口要求在请求中设置一个username头部,用于身份鉴权。

1

2

3

4

5

6

7

@FeignClient(name = "kafka-client", url = "http://kafka.xxx.com")

public interface KafkaClient {

    @GetMapping(value = "/api/clusterManager/listTopics")

    @Headers( {"cache-control: no-cache", "username: wangyong@xxx.com"})

    TopicsResponse listTopics(@RequestParam("clusterName") String clusterName,

                              @RequestParam("clusterArea") String clusterArea);

}

代码写好好,尝试去进行访问

抛出如下错误信息

1

2

3

4

5

6

7

{

    "timestamp": 1551768926170,

    "status": 500,

    "error": "Internal Server Error",

    "exception": "com.netflix.zuul.exception.ZuulException",

    "message": "pre:AuthAccessFilter"

}

异常堆栈信息如下:

    at feign.FeignException.errorStatus(FeignException.java:62)
    at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:91)
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:134)
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:76)
    at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103)
    at com.sun.proxy.$Proxy147.listTopics(Unknown Source)
    at com.yidian.data.exptmgr.controller.KafkaController.getKafkaTopics(KafkaController.java:35)
    // 省略更多异常堆栈信息

于是我尝试通过debug来找到问题的根源,通过debug我发现feign会先将请求参数构建成Request对象,request信息如下:

request

从图中可看到,该Request实例的headers属性为空,而Request又是根据RequestTemplate模板对象生成的,RequestTemplate实例信息如下:

RequestTemplate

到这里可以看出,问题是出在RequestTemplate的构建构成中,于是我就去跟踪RequestTemplate构建的代码,发现RequestTemplate是根据MethodMetadata构建而成,而MethodMetadata就是对方法配置的抽象。

1

2

3

4

5

6

7

8

9

    RequestTemplate template = resolve(argv, mutable, varBuilder);

      if (metadata.queryMapIndex() != null) {

        // add query map parameters after initial resolve so that they take

        // precedence over any predefined values

        template = addQueryMapQueryParameters(argv, template);

      }

      if (metadata.headerMapIndex() != null) {

        template = addHeaderMapHeaders(argv, template);

      }

从上述代码可以看到,header的设置是由metadata的headerMapIndex 属性决定的,那么,设置headerMapIndex的位置,必然就和Header的解析相关,于是通过查看方法引用

我找到了下面的代码

1

2

3

4

5

6

7

8

9

10

11

12

13

    private void parseHeaders(MethodMetadata md, Method method,

            RequestMapping annotation) {

        // TODO: only supports one header value per key

        if (annotation.headers() != null && annotation.headers().length > 0) {

            for (String header : annotation.headers()) {

                int index = header.indexOf('=');

                if (!header.contains("!=") && index >= 0) {

                    md.template().header(resolve(header.substring(0, index)),

                        resolve(header.substring(index + 1).trim()));

                }

            }

        }

    }

从代码中我们可以清晰的看到,解析过程中是从@RequestMapping或其派生注解的header属性中解析Header的,并且Header的key和value需要用“=”进行分割。

于是我修改成下面的形式,

问题就解决了

1

2

3

4

   @GetMapping(value = "/api/clusterManager/listTopics",

        headers = {"cache-control=no-cache", "username=wangyong@xxx.com"})

    TopicsResponse listTopics(@RequestParam("clusterName") String clusterName,

                              @RequestParam("clusterArea") String clusterArea);


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/Leanky/article/details/104883622
相关文章
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • Redis BloomFilter布隆过滤器原理与实现

    Redis BloomFilter布隆过滤器原理与实现
    Bloom Filter 概念 布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射
  • Java C++算法题解leetcode801使序列递增的最小交换次

    Java C++算法题解leetcode801使序列递增的最小交换次
    题目要求 思路:状态机DP 实现一:状态机 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSwap(int[] nums1, int[] nums2) { int n
  • Mybatis结果集映射与生命周期介绍

    Mybatis结果集映射与生命周期介绍
    一、ResultMap结果集映射 1、设计思想 对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了 2、resultMap的应用场
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计