Feign远程调用

1、Feign 远程调用丢失请求头

/**
 * ReflectiveFeign.class
 * this.dispatch.get(method)).invoke(args) 
 */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (!"equals".equals(method.getName())) {
                if ("hashCode".equals(method.getName())) {
                    return this.hashCode();
                } else {
                    return "toString".equals(method.getName()) ? this.toString() : ((MethodHandler)this.dispatch.get(method)).invoke(args);
                }
            } else {
                try {
                    Object otherHandler = args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                    return this.equals(otherHandler);
                } catch (IllegalArgumentException var5) {
                    return false;
                }
            }
        }
/**
 * SynchronousMethodHandler.class
 * this.executeAndDecode(template, options);
 */
public Object invoke(Object[] argv) throws Throwable {
        // 构造请求模板
        RequestTemplate template = this.buildTemplateFromArgs.create(argv);
        Options options = this.findOptions(argv);
        Retryer retryer = this.retryer.clone();

        while(true) {
            try {
                return this.executeAndDecode(template, options);
            } catch (RetryableException var9) {
                RetryableException e = var9;

                try {
                    retryer.continueOrPropagate(e);
                } catch (RetryableException var8) {
                    Throwable cause = var8.getCause();
                    if (this.propagationPolicy == ExceptionPropagationPolicy.UNWRAP && cause != null) {
                        throw cause;
                    }

                    throw var8;
                }

                if (this.logLevel != Level.NONE) {
                    this.logger.logRetry(this.metadata.configKey(), this.logLevel);
                }
            }
        }
    }

/**
 * 执行请求并解码
 */
Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
        // 构造请求
        Request request = this.targetRequest(template);
        if (this.logLevel != Level.NONE) {
            this.logger.logRequest(this.metadata.configKey(), this.logLevel, request);
        }

        long start = System.nanoTime();

        Response response;
        try {
            response = this.client.execute(request, options);
            response = response.toBuilder().request(request).requestTemplate(template).build();
        } catch (IOException var12) {
            if (this.logLevel != Level.NONE) {
                this.logger.logIOException(this.metadata.configKey(), this.logLevel, var12, this.elapsedTime(start));
            }

            throw FeignException.errorExecuting(request, var12);
        }

        long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
        if (this.decoder != null) {
            return this.decoder.decode(response, this.metadata.returnType());
        } else {
            CompletableFuture<Object> resultFuture = new CompletableFuture();
            this.asyncResponseHandler.handleResponse(resultFuture, this.metadata.configKey(), response, this.metadata.returnType(), elapsedTime);

            try {
                if (!resultFuture.isDone()) {
                    throw new IllegalStateException("Response handling not done");
                } else {
                    return resultFuture.join();
                }
            } catch (CompletionException var13) {
                Throwable cause = var13.getCause();
                if (cause != null) {
                    throw cause;
                } else {
                    throw var13;
                }
            }
        }
    }


/**
 * Feign在远程调用之前要构造请求,会调用很多的拦截器
 * Iterator var2 = this.requestInterceptors.iterator();
 */
Request targetRequest(RequestTemplate template) {
        Iterator var2 = this.requestInterceptors.iterator();

        while(var2.hasNext()) {
            RequestInterceptor interceptor = (RequestInterceptor)var2.next();
            interceptor.apply(template);
        }

        return this.target.apply(template);
    }

默认的请求模板

 构造的请求

2、Feign 远程调用异步情况下丢失上下文

3、解决feign远程调用丢失请求头、异步情况丢失上下文

@Override
    public OrderConfirmVO getOrderConfirmVO() throws Exception {
        // 获取原生请求信息
        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();

        // 获取当前登录用户
        MemberVO member = LoginInterceptor.threadLocal.get();

        OrderConfirmVO orderConfirmVO = new OrderConfirmVO();

        CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() -> {
            // 共享原生请求信息,解决feign远程调用异步情况丢失上下文
            RequestContextHolder.setRequestAttributes(attributes);
            // 远程获取用户所有收货地址信息
            R r = memberFeignService.memberAddresses(member.getId());
            List<MemberAddressVO> addresses = r.getData("memberAddresses", new TypeReference<List<MemberAddressVO>>() {});
            orderConfirmVO.setAddresses(addresses);
        }, executor);

        CompletableFuture<Void> itemFuture = CompletableFuture.runAsync(() -> {
            // 共享原生请求信息,解决feign远程调用异步情况丢失上下文
            RequestContextHolder.setRequestAttributes(attributes);
            // 远程获取用户购物车信息
            R r = cartFeignService.getUserCartItems();
            List<CartItemVO> cartItems = r.getData("cartItems", new TypeReference<List<CartItemVO>>() {});
            orderConfirmVO.setCartItems(cartItems);
        }, executor).thenRunAsync(() -> {
            List<CartItemVO> cartItems = orderConfirmVO.getCartItems();
            List<Long> skuIds = cartItems.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
            R r = wareFeignService.getSkuHasStock(skuIds);
            Map<Long, Boolean> skuStock = r.getData("skuStock", new TypeReference<Map<Long, Boolean>>() {});
            orderConfirmVO.setSkuStock(skuStock);
        }, executor);

        // TODO 远程获取优惠信息

        // 防重令牌
        String token = UUID.randomUUID().toString();
        String tokenKey = OrderConstant.ORDER_TOKEN_PREFIX + member.getId();
        stringRedisTemplate.opsForValue().set(tokenKey, token, 30, TimeUnit.MINUTES);
        orderConfirmVO.setOrderToken(token);

        CompletableFuture.allOf(addressFuture, itemFuture).get();


        return orderConfirmVO;
    }
/**
 * 解决feign远程调用丢失请求头、异步情况丢失上下文
 */
@Configuration
public class FeignConfig {

    @Bean
    public RequestInterceptor requestInterceptor() {

        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                // RequestContextHolder 获取原生请求信息
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                // 异步情况丢失上下文,request 为 null
                if (attributes != null) {
                    // 获取原生请求
                    HttpServletRequest request = attributes.getRequest();
                    if (request != null) {
                        // 给新请求同步cookie
                        requestTemplate.header("Cookie", request.getHeader("Cookie"));
                    }
                }
            }
        };

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值