feign微服务之间传递请求头数据

这篇具有很好参考价值的文章主要介绍了feign微服务之间传递请求头数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

直接在微服务远程调用中获取请求头数据不能直接获取到.为什么? 看源码

默认情况下feign远程调用的时候不会传递请求头!

远程调用源码:

feign微服务之间传递请求头数据

每一次远程请求的时候都创建了一个新的Request Template对象,在该对象中不包含之前的请求头数据

解决方案:

方案一:在feign接口上添加对应的形式参数即可

弊端:每一个接口想要获取参数都需要在接口方法上添加对应的形式参数.影响代码效率

方案二:使用OpenFeign中的拦截器(RequestInterceptor)来拦截请求,添加请求头。

方案一演示:

FeignClient接口:

@FeignClient(value = "service-cart",fallback = FeignClientFallback.class)//降级方法
public interface FeignClient { 
public Result xxx( 
                  @RequestParam(value = "xx" )Long xx ,
                  @RequestParam(value = "xx" )String xx);
}

Controller远程接口:

@RestController
@RequestMapping("/x/x/x")
public class Controller {

    @GetMapping("/x/x/x")
    public Result aaa(
            @RequestParam(value = "xx" )Long xx ,
            @RequestParam(value = "xx" )String xx
             ) {
        return Result.ok() ;
    }
}

//@RequestParam 通过传参的方法传递过去,并非从请求头上拿
FeignClient.aaa(xx,xx); //远程调用时候传参

方案二演示:

思路:在OpenFeign远程调用 定义一个拦截器类实现(RequestInterceptor)接口给RequestTemplate设置上请求头

核心源码

// feign.SynchronousMethodHandler#executeAndDecode
Request targetRequest(RequestTemplate template) {        
    // 在构建目标请求对象的时候,遍历所有的拦截器,
    //   然后调用了apply方法把RequestTemplate作为参数传递过去
    for (RequestInterceptor interceptor : requestInterceptors) {
        interceptor.apply(template);
    }
    return target.apply(template);
}

拦截器类如何获取Controller请求头数据呢?

思路1:通过Map实现

原理:feign的调用链使用的是同一个线程对象

思路2:通过ThreadLocal对象在一个线程中共享HttpServletRequest对象(使用JDK自带的ThreadLocal在一个线程中共享HttpServletRequest对象,原理就是在底层维护了一个Map。)

思路3: 使用spring提供的对象RequestContextHolder进行实现!

原理:底层通过RequestContextListener监听器实现

思路1实现:

获取Controller中请求头思路:

feign的调用链使用的是同一个线程对象

所以可以在Controller中定义一个Map集合,键就是当前线程对象,值就是HttpServletRequest对象

 //定义一个Map,作用是在tController和FeignClientInterceptor(拦截器)中共享HttpServletRequest
    public static final ConcurrentHashMap<Thread, HttpServletRequest> concurrentHashMap =new ConcurrentHashMap<>();

//给map中存request对象

@GetMapping("/xx")//required:传递过来的参数可以有可以无
    public String addCart(HttpServletRequest request, ) {

        concurrentHashMap.put(Thread.currentThread(),request);
}

拦截器类通过map获取请求头数据,设置给RequestTemplate

@Component
@Slf4j
public class FeignClientInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        log.info("FeignClientInterceptor..........");
        HttpServletRequest httpServletRequest = CartController.concurrentHashMap.get(Thread.currentThread());
            //给requestTemplate 添加上对应的请求头中的数据:aa,bbb
        requestTemplate.header("userId",httpServletRequest.getHeader("aa"));
        requestTemplate.header("userTempId",httpServletRequest.getHeader("bbb"));

    }
}

思路2实现:

在Controller中定义一个ThreadLocal对象

public static final  ThreadLocal<HttpServletRequest> threadLocal = new ThreadLocal<>();

然后在方法中调用set方法添加数据(request)

        threadLocal.set(request);

在拦截器中调用get方法就可以拿到HttpServletRequest对象,然后给requestTemplate 添加上对应的请求头中的数据:aa,bbb

 HttpServletRequest httpServletRequest = CartController.threadLocal.get();

 requestTemplate.header("userId",httpServletRequest.getHeader("aa"));
 requestTemplate.header("userTempId",httpServletRequest.getHeader("bbb"));

思路3实现:使用spring提供的对象RequestContextHolder直接在拦截器类获取request对象

//RequestContextHolder对象中获取一个线程内所共享的HttpServletRequest对象
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
//获取到了request对象剩下的同上

思路3的在Controller使用模块中通过RequestContextHolder隐式获取请求头数据

直接在使用模块获取ServletRequestAttributes对象,不需要在参数添加@RequestHeader(value = "xxx")
因为刚才已经用到了request对象
// 获取ServletRequestAttributes对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest requestAttributesRequest = requestAttributes.getRequest();
        String userId = requestAttributesRequest.getHeader("userId");
        String userTempId = requestAttributesRequest.getHeader("userTempId") ;

代码优化:

1.将从RequestContextHolder对象中读取xx和xx数据的代码封装到一个工具类(utilxx),并使用一个实体类返回相关数据:

public class Utils {

    public static UserInfoVo userInfo() {

        // 获取请求对象
        ServletRequestAttributes requestAttributes 
        = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();

        // 判断requestAttributes是否为空
        if(requestAttributes != null) {

            // 获取request对象
            HttpServletRequest request = requestAttributes.getRequest();

            // 从请求对象中获取xx和xx数据
            String userid = request.getHeader("id");
            String username = request.getHeader("name");

            // 封装数据到xxx对象中
            User user = new user() ;
            if(!StringUtils.isEmpty(userId)) {
                userAuthInfoVo.setUserId(Long.parseLong(userId));
            }
            userAuthInfoVo.setUserTempId(username);

            // 返回
            return user ;
        }

        return null ;
    }

}

2.FeignClientInterceptor抽取成公共组件

为了实现FeignClientInterceptor的复用,那么此时可以将FeignClientInterceptor抽取成一个公共的组件


@Slf4j
@Component
public class FeignClientInterceptor implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate template) {
        
        log.info("FeignClientInterceptor拦截器执行了....");

        User user = User.getUser();
        if(user != null) {
            Long userId = user.getUserId();
            if(userId != null) {
                template.header("userId" , String.valueOf(userId)) ;
            }
            template.header("username" , userAuthInfo.getUsername()) ;
        }

    }

}

自定义注解:

因为抽取公共类后包路径不一样会导致扫描不到所以,可以使用自定义注解或@Import解决,这里使用自定义注解

@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@Import(value = EnableFeignClientInterceptor.class)
public @interface EnableFeignClientInterceptor {
}

启动类加上@EnableFeignClientIntercepto即可使用文章来源地址https://www.toymoban.com/news/detail-455228.html

到了这里,关于feign微服务之间传递请求头数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Windows和Linux之间如何传递数据|两台Linux之间如何传递数据

    摘要:我们租用了一台服务器,然后我们想要把我们写的项目上传到自己的Linux服务器中,那么我们应该怎么上传呢?如果我们想要从服务器中下载一些资料,那么又该如何进行呢?看这篇文章将会告诉你答案。 把数据从本地电脑上传到Linux服务器的方式有很多,这里介绍最

    2024年02月03日
    浏览(45)
  • 19.组件之间传递数据

    不同组件传递数据的时候,最好不要直接传递复杂数据类型(比如对象,数组) 前端需要处理的数据层级一般不会很多,需要在多处使用的数据一般会被放到数据库中 目录 1  组件的关系 2  父向子传递数据-props 3  子向父传递数据-自定义事件 4  父子组件同步数据 v-model与

    2024年02月09日
    浏览(55)
  • SpringCloud微服务之间如何进行用户信息传递(涉及:Gateway、OpenFeign组件)

    在业务微服务中通过工具类获取当前用户信息 网关微服务(Gateway)往业务微服务传递用户信息 业务微服务之间通过OpenFeign传递用户信息 只要把上面两处打通,然后业务微服务在通过拦截器获取到用户信息,之后再将用户信息存在ThreadLocal中,这样我们就可以实现在业务微服

    2024年02月13日
    浏览(54)
  • SpringCloud Alibaba(一)微服务简介+Nacos的安装部署与使用+Nacos集成springboot实现服务注册+Feign实现服务之间的远程调用+负载均衡+领域划分

    目录 一.认识微服务 1.0.学习目标 1.1.单体架构 单体架构的优缺点如下: 1.2.分布式架构 分布式架构的优缺点: 1.3.微服务 微服务的架构特征: 1.4.SpringCloud 1.5Nacos注册中心 1.6.总结 二、Nacos基本使用安装部署+服务注册 (一)linux安装包方式单节点安装部署 1. jdk安装配置 2. na

    2024年02月09日
    浏览(46)
  • Postman接口之间传递数据 实现接口关联

    在我们使用Postman进行接口测试的时候,经常会遇到一个接口的返回结果是另一个接口所需要的请求参数。 例如 :我们再测试时,一般需要先去调用登录接口,进行登录,并返回 token 相关信息,随后我们进行调用其它接口时可能会需要携带 token 来完成对应接口所实现的功能

    2023年04月21日
    浏览(46)
  • 小程序页面之间数据传递的五种方法

    使用 wx.navigateTo() 时,在 url 中拼接,这种方法适用于数据量少的情况 跳转前A页面在 url 中拼接参数,参数与路径之间使用 ? 分隔,参数键与参数值用 = 相连,不同参数用 分隔; 跳转到B页面在生命周期函数 onLoad 中接收 如果需要传递对象或数组,需先将对象或数据转为JSON字符

    2024年02月10日
    浏览(47)
  • 互联网大厂技术-HTTP请求-Springboot整合Feign更优雅地实现Http服务调用

    目录 一、SpringBoot快速整合Feign 1.添加Pom依赖 2.启动类添加注解 3.引用Feign服务 二、为请求添加Header的3种方式 1.添加固定header 2.通过接口签名添加header 3.动态添加header 三、为请求添加超时配置 1.默认超时时间 3.超时异常 4.全局超时配置 5.为单个服务设置超时配置 四、为请求配

    2024年02月04日
    浏览(61)
  • 前端HTML网页之间传递数据多种办法,附代码案例

       目前常用的有三种办法 session传递,cookie传递,url传递 url会暴露参数,其余的两个是保存在服务端和浏览器中,不会暴露在地址栏里面 使用url:   下面依次介绍 案例说明:  在HTML1中,我们使用 form 标签将数据提交到HTML2页面,并设置 method 为 post , action 为HTML2的文件路

    2024年02月09日
    浏览(104)
  • 在 React 中,props(属性)用于在组件之间传递数据

    在 React 中,props(属性)用于在组件之间传递数据。它是父组件向子组件传递信息的一种方式,通过 props,父组件可以向子组件传递数据、回调函数、配置项等。 注意: props 是只读的,它的值由父组件传递给子组件时确定,并且在子组件中不能直接修改。如果子组件需要改

    2024年02月15日
    浏览(51)
  • 微服务之间Feign调用无法解析IPage报错问题:Cannot construct instance of `com.baomidou.mybatisplus.core.metadata.IPage

    最新在做一个对外提供基础信息的需求,我在A服务中写了一个分页接口,本以为很简单的我在B服务用 Feign 调用一下就可以了。 可想并没有这么简单,报错了: 从源码中我们可以看到:这里是分页,而 com.baomidou.mybatisplus.core.metadata.IPage是一个接口(interface),源代码如下: 因

    2024年04月27日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包