• feign远程调用时如何在请求头加入数据


    1.先提出问题的解决方案
       通过实现Feign的RequestInterceptor(拦截器)接口,重写里面的apply方法,为RequestTemplate添加自定义的请求头的参数及数据的传入。请求最开始进来的时候,就会进入到这个拦截器中,业务代码中进行远程调用的时候还会进入到这个请求里面来。
    
    1. @Component
    2. public class FeignClientsExtendInterceptor implements RequestInterceptor {
    3. @Override
    4. public void apply(RequestTemplate requestTemplate) {
    5. // 此种方式是线程安全的
    6. ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder
    7. .getRequestAttributes();
    8. // 不为空时取出请求中的header 原封不动的设置到feign请求中
    9. if (null != attributes) {
    10. HttpServletRequest request = attributes.getRequest();
    11. if (null != request) {
    12. // 遍历设置 也可从request取出整个Header 写到RequestTemplate 中
    13. Enumeration headerNames = request.getHeaderNames();
    14. if (headerNames != null) {
    15. while (headerNames.hasMoreElements()) {
    16. String name = headerNames.nextElement();
    17. String values = request.getHeader(name);
    18. requestTemplate.header(name, values);
    19. }
    20. }
    21. }
    22. }
    23. // 处理请求体参数信息
    24. // feign调用get接口的时候,会报出405 Request method ‘POST‘ not supported的错误
    25. // 当你不需要将请求体内的信息也传输过去的,可以通过注释处理请求体信息的代码来解决
    26. // 原因是feign底层发请求的时候,发现请求体带有参数会自动转成post请求。
    27. /*
    28. Enumeration bodyNames = request.getParameterNames();
    29. StringBuilder body = new StringBuilder();
    30. if (bodyNames != null) {
    31. while (bodyNames.hasMoreElements()) {
    32. String name = bodyNames.nextElement();
    33. String values = request.getParameter(name);
    34. body.append(name).append("=").append(values).append("&");
    35. }
    36. }
    37. if (body.length() != 0) {
    38. body.deleteCharAt(body.length() - 1);
    39. requestTemplate.body(body.toString());
    40. }
    41. */
    42. }
    43. }

    2.业务场景(保证后面的请求中,调用者的信息一致)

    (1)消费了MQ消息,发起了远程调用。

            也就是这个时候是没有请求相关的信息的,但是在feign发起请求的时候,需要保证请求头里的信息是当前线程的相关信息,这个时候可以把需要的相关信息放入一个线程副本中去,通过继承RequestContextHolder或者重写一个相似的类,将当前线程的信息放置进去,然后在feign发起远程调用的时候,将所需信息取出来,放入请求头中。

    (2)同一线程

            前端请求时,会在请求头中带上一系列的校验参数,调用我的服务,需要再去调用其他服务。在其他服务中, 需要对请求头中的信息做提取或者校验。

            feign远程调用的时候,底层是对参数进行了封装然后进行请求,是一次新的请求,那么前端传入请求中的头文件信息自然不会被传过去,所以可以通过重写RequestInterceptor,将请求头的信息原封不动的复制进去。

    (3)多线程异步调用其他微服务

            上述重写的代码可能就获取不到主线程的请求信息了,主要原因是:RequestContextHolder来获取request信息,发现异步调用时,主线程结束后,子线程就获取不到request,会报出错误信息。

    解决方式1:

            通过获取到主线程的请求,在前端调用的时候,前端请求会进来,这个时候开启子线程共享,那么在后面的业务执行时,发现异步调用时,主线程结束后,子线程是可以获取request的相关信息的。

    1. ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    2. // 在上面代码后面开启子线程共享
    3. RequestContextHolder.setRequestAttributes(servletRequestAttributes,true);//设置子线程共享

    解决方式2:

            与(2)同一线程的处理方式类似,将主线程的request和session信息放进ThreadLocal里,透传到子线程再去获取。

  • 相关阅读:
    upload-labs文件上传靶场实操
    linux docker安装SqlServer2019
    竞赛 基于深度学习的行人重识别(person reid)
    SpringBoot集成Spring Data JPA项目实操
    宝塔等Nginx环境添加允许跨域Header头
    141. 环形链表
    MySQL数据库常用命令大全(完整)(表格形式)
    C++模拟实现——红黑树
    windows 下 c++ 二维码生成库
    网站部署:使用Nginx部署vue项目到阿里云服务器
  • 原文地址:https://blog.csdn.net/weixin_42218169/article/details/125901794