Feign远程调用丢失请求头或异步情况丢失请求上下文

578 阅读1分钟

Feign在远程调用之前要构造请求,会调用很多拦截器来对请求进行增强,如果没有的拦截器,会创建一个新的request请求,这个请求里什么都没有

image.png

解决:添加拦截器解决远程调用丢失请求头

package cn.cloud.xmall.order.config;

import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description: Feign拦截器
 * @author: Freedom
 * @QQ: 1556507698
 * @date:2022/4/9 13:30
 */
@Configuration
public class XmallFeignConfig {
    @Bean
    public RequestInterceptor requestInterceptor() {
        return template -> {
            //使用RequestContextHolder拿到Controller刚进来的请求数据,ServletRequestAttributes 父类实现了 RequestAttributes
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest(); //老请求
            //同步请求头信息 cookie
            String cookie = request.getHeader("Cookie"); //拿到老请求的cookie
            //给新请求同步老请求cookie
            template.header("Cookie",cookie ); //cookie放到新请求理
        };
    }

    ;

}


解决:异步情况丢失请求上下文

image.png

在自己的线程下再来共享requestAttributes就可以解决


        //开启异步任务
        CompletableFuture<Void> getAddress = CompletableFuture.runAsync(() -> {
            //1.远程查询所有的收货地址列表
            RequestContextHolder.setRequestAttributes(requestAttributes);
            List<MemberAddressVo> address = memberFeignService.getAddress(memberRespVo.getId());
            confirmVo.setAddress(address);
        }, executor);

错误记录:java.lang.IllegalStateException:Duplicate key

原因
Map中出现了和被转换的List中重复的key记录

 try {
       //发起远程请求
        R skuHasStock = wareFeignService.getSkusHasStock(skuIds);
        //转换为map
        TypeReference<List<SkuHasStockVo>> typeReference = new TypeReference<List<SkuHasStockVo>>() {};
        stockMap = skuHasStock.getData(typeReference).stream()
                .collect(
                        Collectors.toMap(
                                SkuHasStockVo::getSkuId,
                                item -> item.getHasStock(),
                                (v1,v2)->v1)
                        );
        }catch (Exception e){
            log.error("库存服务查询异常:原因{}",e);
        }

解决方案
两个key 相同时,保留先存进去的那个元素

Collectors.toMap(
       SkuHasStockVo::getSkuId,
        item -> item.getHasStock(),
        (v1,v2)->v1)
);