解决在微服务环境下远程调用feign和异步线程存在请求数据丢失问题

目录
  • 一、无异步线程得情况下feign远程调用:
    • 1、登录拦截器:
    • 2.问题示例图:
    • 3.解决方法:
      • 解决方式(高亮部分):从总线中获取request数据放入子线程中
  • 二、异步情况下丢失上下文问题:

一、无异步线程得情况下feign远程调用:

1、登录拦截器:

@Component
public class LoginUserInterceptor implements HandlerInterceptor {
    public static ThreadLocal<MemberResVo> loginUser = new ThreadLocal<>();
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //获取登录用户的键
        MemberResVo attribute = (MemberResVo) request.getSession().getAttribute(AuthServerConstant.LONG_USER);
        if (attribute!=null){
            loginUser.set(attribute);
            return true;
        }else {
            request.getSession().setAttribute("msg","请先进行登录!");
            response.sendRedirect("http://auth.gulimall.com/login.html");
            return false;
        }
    }
}

2.问题示例图:

3.解决方法:

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
@Configuration
public class GuliFeignConfig {
    //fegin过滤器
    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            public void apply(RequestTemplate template) {
                //上下文环境保持器,拿到刚进来这个请求包含的数据,而不会因为远程数据请求头被清除
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = attributes.getRequest();//老的请求
                if (request != null) {
                    //同步老的请求头中的数据,这里是获取cookie
                    String cookie = request.getHeader("Cookie");
                    template.header("Cookie", cookie);
                }
            }
        };
    }
}

二、异步情况下丢失上下文问题:

① 在同一线程下进行远程调用,即一连串调用的情况下OrederService通过远程调用先查找adress信息,再查找cart信息,则仅需配置GuliFeignConfig就够了

② 由于采用的异步任务,所以101、102线程在自己的线程中调用登录拦截器interceptor,而其实只有在72号线程中登陆拦截器才进行放行(有请求头数据),这就导致101、102的request为null

解决方式(高亮部分):从总线中获取request数据放入子线程中

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes()
@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity>
implements OrderService {
    @Autowired
    MemberFeignService memberFeignService;
    @Autowired
    CartFeginService cartFeginService;
    @Autowired
    ThreadPoolExecutor executor;
    @Autowired
    WmsFeignService wmsFeignService;

    /**
     * 订单确认页返回的数据
     * @return
     */
    @Override
    public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
        OrderConfirmVo confirmVo = new OrderConfirmVo();
        MemberResVo memberResVo = LoginUserInterceptor.loginUser.get();
        //从主线程中获得所有request数据
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
            //1、远程查询所有地址列表
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = memberFeignService.getAddress(memberResVo.getId());
            confirmVo.setAddress(address);
        }, executor);

        //2、远程查询购物车所选的购物项,获得所有购物项数据
        CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
            //放入子线程中request数据
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> items = cartFeginService.getCurrentUserCartItems();
            confirmVo.setItem(items);
        }, executor).thenRunAsync(()->{
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<OrderItemVo> items = confirmVo.getItem();
            List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            //远程调用查询是否有库存
            R hasStock = wmsFeignService.getSkusHasStock(collect);
            //形成一个List集合,获取所有物品是否有货的情况
            List<SkuStockVo> data = hasStock.getData(new TypeReference<List<SkuStockVo>>() {
            });
            if (data!=null){
                //收集起来,Map<Long,Boolean> stocks;
                Map<Long, Boolean> map = data.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
                confirmVo.setStocks(map);
            }
        },executor);
        //feign远程调用在调用之前会调用很多拦截器,因此远程调用会丢失很多请求头

        //3、查询用户积分
        Integer integration = memberResVo.getIntegration();
        confirmVo.setIntegration(integration);
        //其他数据自动计算

        CompletableFuture.allOf(getAddressFuture,cartFuture).get();
        return confirmVo;
    }

}

到此这篇关于解决在微服务环境下远程调用feign和异步线程存在请求数据丢失问题的文章就介绍到这了,更多相关feign远程调用请求丢失内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Feign远程调用参数里面内容丢失的解决方案

    目录 Feign远程调用参数里面内容丢失 举个例子 解决方法 Feign远程调用细节--丢失数据 同步调用 异步调用 Feign远程调用参数里面内容丢失 举个例子 服务A提供了如下接口(注意这里的参数url是一个地址): @GetMapping("/getSample") public String getSample(@RequestParam String url){      //此处省略逻辑...... } 服务B需要调用服务A的接口,调用如下: sampleFeignClie

  • Feign远程调用传递对象参数并返回自定义分页数据的过程解析

    目录 Feign介绍 Feign测试 1.在yml文件里面增加了配置信息 2.在客户端pom.xml文件中引入的依赖(消费者端) 3.服务调用端接口为 4.服务调用端Service代码 5.服务调用端Fallback为 6.服务提供端代码为 7.测试 Feign调用分页接口报错:MethodhastoomanyBodyparameters 解决方法 Feign介绍 Feign是Netflix公司开源的轻量级rest客户端,使用Feign可以非常方便的实现Http 客户端.Spring Cloud

  • 使用Feign远程调用时,序列化对象失败的解决

    Feign远程调用序列化对象失败 最近在搭建一个SpringCloud的微服务时,遇到了一个问题,在使用Feign远程调用时报错,返回对象没有无参构造方法,有其他的含参数的构造方法. 本地自己搭建的微服务目录大概如下,才刚开始,后续会逐渐补充优化迭代,有兴趣的可以fork下地址: https://github.com/zhanghailang123/MyCloud 给与指导意见. Eureka:注册中心服务端,采用Eureka注册中心 EurekaClientA:其中的一个Eureka服务端,命

  • Feign远程调用Multipartfile参数处理

    目录 Feign远程调用Multipartfile参数 解决方案 Feign远程调用传参问题 Feign远程调用Multipartfile参数 今天在写业务代码的时候遇到的问题, 前端请求A服务,能正确把参数给到A服务<参数里面包括文件类型的 Multipartfile>,但是当A服务调用B服务时把文件参数丢过去,那边接收不到,并且会报Multipartfile 参数错误. 在网上找到了答案,特此记录一下: 解决方案 必须的 在你的fegin 服务接口暴露的地方新建一个配置类. package

  • spring cloud feign实现远程调用服务传输文件的方法

    实践案例包括两个项目,服务提供者项目名:upload-service,调用服务项目名:upload-client,主要给出两个服务之间的调用过程,文件上传功能不提供 项目框架:spring-boot 2.0.1.RELEASE.spring-cloud Finchley.RELEASE 依赖: <dependency> <groupId>io.github.openfeign.form</groupId> <artifactId>feign-form<

  • feign远程调用无法传递对象属性405的问题

    目录 feign远程调用无法传递对象属性 get请求405错误 使用feign请求远端 客户端 服务端 feign.FeignException$MethodNotAllowed status405readingxxx#yyy(Integer) 异常信息 详细信息 解决方案 feign远程调用无法传递对象属性 get请求405错误 通过查看feign底层源码,feign底层使用的是httpurlconnection的工具,而进行传递body的时候,会调用getOutputStrean方法,里边会

  • 解决在微服务环境下远程调用feign和异步线程存在请求数据丢失问题

    目录 一.无异步线程得情况下feign远程调用: 1.登录拦截器: 2.问题示例图: 3.解决方法: 解决方式(高亮部分):从总线中获取request数据放入子线程中 二.异步情况下丢失上下文问题: 一.无异步线程得情况下feign远程调用: 1.登录拦截器: @Component public class LoginUserInterceptor implements HandlerInterceptor { public static ThreadLocal<MemberResVo> lo

  • 详解Spring Cloud微服务架构下的WebSocket解决方案

    WebSocket在现代浏览器中的应用已经算是比较普遍了,在某些业务场景下,要求必须能够在服务器端推送消息至客户端.在没有WebSocket的年代,我们使用过dwr,在那个时候dwr真实一个非常棒的方案.但是在WebSocket兴起之后,我们更愿意使用标准实现来解决问题. 首先交代一下,本篇文章不讲解WebSocket的配置,主要讲的是针对在微服务架构集群模式下解决方案的选择. 微服务架构大家应该都不陌生了,在微服务架构下,服务是分布式的,而且为了保证业务的可用性,每个服务都是以集群的形式存在.

  • spring boot微服务场景下apollo加载过程解析

    目录 集成使用 1.添加gradle依赖 2.配置application.properties 必须配置 可选配置 加载过程解析 postProcessEnvironment方法逻辑解析 initialize方法逻辑解析 结语 集成使用 1.添加 gradle 依赖 implementation "com.ctrip.framework.apollo:apollo-client:1.6.0" 2.配置 application.properties apollo 自身的配置共包含 9 项

  • 使用 Apache Dubbo 实现远程通信(微服务架构)

    目录 前言 1. Dubbo 基础知识 1.1 Dubbo 是什么 1.2 Dubbo 的架构图 1.3 Spring Cloud 与 Dubbo 的区别 1.4 Dubbo 的特点 1.5 Dubbo 的 6 种容错模式容错模式 1.7 主机绑定规则 2. 构建 Dubbo 服务提供方 2.1 构建服务接口模块 2.2 添加 pom.xml 依赖文件 2.3 修改 application.yml 配置文件 2.4 在主程序类上添加注解 2.5 实现 2.1 定义的接口 3. 构建 Dubbo

  • OpenFeign实现远程调用

    本文实例为大家分享了OpenFeign远程调用实现的具体代码,供大家参考,具体内容如下 什么是OpenFeign OpenFeign目前是Spring Cloud 二级子项目.平时说的Feign指的是Netflix下的Feign,现在我们学习的是OpenFeign,是Spring提供的. OpenFeign是一种声明式.模板化的HTTP客户端(仅在Application Client中使用)(称OpenFeign作用:声明式服务调用).声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操

  • SpringCloud微服务基础简介

    一.什么是Spring Cloud? SpringCloud 对常见的分布式系统模式提供了简单易用的编程模型,帮助开发者构建弹性.可靠.协调的应用程序. SpringCloud 是在SpringBoot的基础上构建的,使开发者可以轻松入门并快速提高工作效率. SpringCloud 提供了一套微服务解决方案,包括服务注册与发现,配置中心,全链路监控,服务网关,负载均衡,熔断器等组件,除了基于NetFlix的开源组件做高度抽象封装之外,还有一些选型中立的开源组件. SpringCloud 为开发人

  • 详解OpenFeign服务调用(微服务)

    目录 OpenFeign服务调用 OpenFeign是什么 Feign能干什么 Feign集成了Ribbon Feign和OpenFeign两者区别 OpenFeign服务调用 OpenFeign超时控制 OpenFeign日志增强 OpenFeign服务调用 OpenFeign是什么 官方文档 Github地址 Feign is a declarative web service client. It makes writing web service clients easier. To u

  • spring cloud中微服务之间的调用以及eureka的自我保护机制详解

    上篇讲了spring cloud注册中心及客户端的注册,所以这篇主要讲一下服务和服务之间是怎样调用的 不会搭建的小伙伴请参考我上一篇博客:idea快速搭建spring cloud-注册中心与注册 基于上一篇的搭建我又自己搭建了一个客户端微服务: 所以现在有两个微服务,我们所实现的就是微服务1和微服务2之间的调用 注册中心就不用多说了,具体看一下两个微服务 application.yml配置也不用说了,不知道怎么配置的请参考我上篇博客 在project-solr中的constroller中: @R

  • Java中dubbo+zookeeper微服务架构简介

    目录 1.Apache Dubbo概述 1.1.Dubbo简介 1.2.Dubbo的服务架构 2.服务注册中心 Zookeeper 2.1.ZooKeeper介绍 2.2.ZooKeeper安装 2.3.启动 ZooKeeper 3.ZooKeeper快速入门 3.1.服务提供方 3.2.服务消费方 3.3.问题思考 4. Dubbo管理控制台 4.1.安装 5. Dubbo相关配置 5.1.包扫描 5.2.Dubbo 协议 5.3.负载均衡 5.4. Dubbo无法发布被事务代理的服务 1.A

  • 解析SpringCloud简介与微服务架构

    1. 微服务架构 1.1 微服务架构理解 微服务架构(Microservice Architecture)是一种架构概念,旨在通过将功能分解到各个离散的服务中以实现对解决方案的解耦.你可以将其看作是在架构层次而非获取服务的类上应用很多SOLID原则.微服务架构是个很有趣的概念,它的主要作用是将功能分解到离散的各个服务当中,从而降低系统的耦合性,并提供更加灵活的服务支持. 概念:把一个大型的单个应用程序和服务拆分为数个甚至数十个的支持微服务,它可扩展单个组件而不是整个的应用程序堆栈,从而满足服务等

随机推荐