HttpRetryException: cannot retry due to redirection, in streaming mode

错误栈

2021-07-30 16:56:09.979 ERROR 18697 --- [nio-8000-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.RetryableException: cannot retry due to redirection, in streaming mode executing POST http://gulimall-order/order/order/listWithItem] with root cause

java.net.HttpRetryException: cannot retry due to redirection, in streaming mode

今天openFeign调用一个服务的时候发生这个问题,没有详细的提示,网上也是各种解决办法,不唯一不典型,只能debug进入各个节点看问题。
先捋一下 远程调用的执行过程
1、浏览器发送http请求(携带请求头)
2、进过本地host 路由至虚拟机80端口的nginx
3、nginx负载均衡至88端口的网关服务
4、网关将请求派送至指定服务,再根据携带的请求头 到指定路径处理请求

在请求入口,远程调用开始的地方和远程方法的具体实现打上断点
HttpRetryException: cannot retry due to redirection, in streaming mode_第1张图片
HttpRetryException: cannot retry due to redirection, in streaming mode_第2张图片
发现无法进入远程实现就抛出了异常,判断是拦截器中抛出了异常

在拦截器中打上断点,发现远程获取session时出现了错误,且session值也与页面存储的不一至。所以获取不到登陆信息。
在这里插入图片描述
在这里插入图片描述

HttpRetryException: cannot retry due to redirection, in streaming mode_第3张图片
这是由于 feign 的远程调用丢失请求头问题,debug feign 的远程发起源码

debug feign源码的全过程与step_into节点
在这里插入图片描述
HttpRetryException: cannot retry due to redirection, in streaming mode_第4张图片
HttpRetryException: cannot retry due to redirection, in streaming mode_第5张图片
HttpRetryException: cannot retry due to redirection, in streaming mode_第6张图片
HttpRetryException: cannot retry due to redirection, in streaming mode_第7张图片
发现源码中 一直在构建一个 请求模版 template ,这是feign用于发起远程调用的模版,其中 Cookie 的请求一直空,且在最后一步循环requestInterceptors时也没有加入任何模版,所以问题出在这里,没有将Cookie加入template的请求头中,导致远程调用无法获取到 session 值(之前的session值可是是feign自己生成的)。

解决办法 往容器中添加自定义的 requestInterceptor 以增强 template ,上面有说,feign会循环容器中的 requestInterceptor 将其都 apply 进template中。

@Configuration
public class GuliFeignConfig {

    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor() {
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate template) {
                //1、拿到刚进来的这个老请求
                ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

                if (attributes != null) {

                    System.out.println("RequestInterceptor线程。。。" + Thread.currentThread().getId());
                    HttpServletRequest request = attributes.getRequest();//老请求
                    if (request != null) {
                        //同步请求头信息,cookie
                        template.header("Cookie", request.getHeader("Cookie"));
                        //给新请求同步老请求的cookie
                        System.out.println("feign远程之前先这里 apply 方法");
                    }
                }
            }
        };
    }
}

再次debug,请求头中已经有Cookie 头 ,问题解决
HttpRetryException: cannot retry due to redirection, in streaming mode_第8张图片

你可能感兴趣的:(错题集,BUG,技巧,spring,cloud,java,分布式)