首页 > 其他分享 >feign远程调用丢失请求头

feign远程调用丢失请求头

时间:2022-10-23 10:11:44浏览次数:48  
标签:feign 调用 return 请求 Object request 丢失 template

1、feign 远程调用丢失请求头的问题

原因:feign不会同步request的请求头。

解决方案:使用interceptor将用户请求的请求头设置给feign代理的请求

/**
 * @DESCRIPTION feign的请求拦截器,用于将用户请求头设置给feign代理后的请求,防止代理后丢失请求头
 * @Author yaya
 * @DATE 2022/10/7
 */
@Configuration
public class FeignInterceptor {


    @Bean("requestInterceptor")
    public RequestInterceptor requestInterceptor(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                // 通过RequestContextHolder拿到用户的request
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();
                String cookie = request.getHeader("Cookie");
                // 将用户的cookie设置给feign代理后的请求
                requestTemplate.header("Cookie", cookie);
            }
        };
    }
}

源代码跟踪:

1、feign远程调用首先会进ReflectiveFeign.invoke方法

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 {
					// 如果不是hashCode、toString方法则会调用目标方法
                    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;
                }
            }
        }

2、然后会进到SynchronousMethodHandler.invoke方法

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 var13) {
            if (this.logLevel != Level.NONE) {
                this.logger.logIOException(this.metadata.configKey(), this.logLevel, var13, this.elapsedTime(start));
            }

            throw FeignException.errorExecuting(request, var13);
        }

        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 var12) {
                Throwable cause = var12.getCause();
                if (cause != null) {
                    throw cause;
                } else {
                    throw var12;
                }
            }
        }
    }

在executeAndDecode方法中会执行一行代码Request request = this.targetRequest(template);这个方法就是处理request的逻辑。

3、targetRequest处理request

    Request targetRequest(RequestTemplate template) {
		// 遍历执行interceptor
        Iterator var2 = this.requestInterceptors.iterator();

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

        return this.target.apply(template);
    }

在targetRequest方法中会遍历执行interceptor。
private final List requestInterceptors;
我们往容器中放的interceptor就会被执行,request中就会有请求头了。

2、feign异步情况丢失上下文

原因:异步请求,request不是同一个,threadLocal中获取不到。

解决方案:在异步编排时手动在新线程中共享下数据:RequestContextHolder.setAttribute()。

标签:feign,调用,return,请求,Object,request,丢失,template
From: https://www.cnblogs.com/yanghuanxi/p/16817992.html

相关文章

  • python 调用Adobe Acrobat 将pdf 转 excel
    最近需要批量转换一些pdf扫描件,就开始找相关的python包花了不少时间试了下pdfplumber,pypdf2,camelot这几个包发现都不能成功的转化,原因就在于手上的pdf是扫描件,......
  • apipost动态获取登录token,其他接口同步调用
    1、新增登录接口,接口返回值包含token信息接口信息   返回值   2、在登录接口的后执行脚本,添加环境变量 apt.environment.set("accessToken",response.js......
  • 自动化测试 - php调用jenkins-api构建job
    背景:前一节搭建jenkins并创建了job任务后,用户可以在jenkins平台手动点击构建来执行pytest自动化任务,想实现一个从web界面去触发构建jenkins中的job任务,在这选择使用php来调......
  • TypeScript 此表达式不可调用。 类型 "Number" 没有调用签名。ts(2349) Snake.ts(6
    TS报错:此表达式不可调用。类型"String"没有调用签名。ts(2349)Snake.ts(67,63): 是否缺少分号?letXX=(this.bodies[i-1]asHTMLElement).offsetLeftlet......
  • 齐博X1-栏目的调用1
    本节来说明下系统提供的几个栏目调用的方法一节我们制作了一个公共导航,本节我们在首页index中演示下栏目的相关调用至于其他的数据内容,参考第二季的标签调用即可,直接{qb:t......
  • 齐博X1-栏目的调用2
    fun('sort@fathers',$fid,'cms') 获取上层多级栏目这样的,比如我们现在所属第三级栏目,现在可以利用这个函数获取第二级和第一级的栏目,当然自身也会被调用出来,所以此函数用......
  • 齐博X1-栏目的调用3
    本节继续说明栏目的调用之同级别栏目同级栏目的调用  fun('sort@brother',$fid,'cms')这个函数用的比较多,特别是栏目页,在一个页面会把一个父级栏目下的子级栏目全部列......
  • pybullet实现SlideBar的封装,任何机械臂可直接调用API完成SlideBars控制
    我将文章发表在了古月居,一起来看看吧!​......
  • HTML调用摄像头和/或麦克风
    API:getUserMedia函数调用摄像头和麦克风API简介HTML5的getUserMediaAPI为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖......
  • C++调用C#DLL并调试
    使用C++来调用C#DLL并且调试程序环境:使用VSstudio2019C#项目的设置1、C#->属性->应用程序->目标框架->.NETFramework42、C#->属性->调试->调试程......