Feign远程调用丢失请求头问题

admin
2022-03-10 / 0 评论 / 32 阅读 / 正在检测是否收录...

openFeign远程调用丢失请求头

feign在远程调用之前要构造请求,调用会经过很多拦截器。丢失请求头原因,是远程调用重新构建了request请求,新的request没有请求头headr。

解决方案:定义一个feign的拦截器

先来看一下feign远程调用类SynchronousMethodHandler

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package feign;

import feign.InvocationHandlerFactory.MethodHandler;
import feign.Logger.Level;
import feign.Request.Options;
import feign.codec.Decoder;
import feign.codec.ErrorDecoder;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

final class SynchronousMethodHandler implements MethodHandler {
    private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
    private final MethodMetadata metadata;
    private final Target<?> target;
    private final Client client;
    private final Retryer retryer;
    private final List<RequestInterceptor> requestInterceptors;
    private final Logger logger;
    private final Level logLevel;
    private final feign.RequestTemplate.Factory buildTemplateFromArgs;
    private final Options options;
    private final ExceptionPropagationPolicy propagationPolicy;
    private final Decoder decoder;
    private final AsyncResponseHandler asyncResponseHandler;

    private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors, Logger logger, Level logLevel, MethodMetadata metadata, feign.RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder, boolean decode404, boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy, boolean forceDecoding) {
        this.target = (Target)Util.checkNotNull(target, "target", new Object[0]);
        this.client = (Client)Util.checkNotNull(client, "client for %s", new Object[]{target});
        this.retryer = (Retryer)Util.checkNotNull(retryer, "retryer for %s", new Object[]{target});
        this.requestInterceptors = (List)Util.checkNotNull(requestInterceptors, "requestInterceptors for %s", new Object[]{target});
        this.logger = (Logger)Util.checkNotNull(logger, "logger for %s", new Object[]{target});
        this.logLevel = (Level)Util.checkNotNull(logLevel, "logLevel for %s", new Object[]{target});
        this.metadata = (MethodMetadata)Util.checkNotNull(metadata, "metadata for %s", new Object[]{target});
        this.buildTemplateFromArgs = (feign.RequestTemplate.Factory)Util.checkNotNull(buildTemplateFromArgs, "metadata for %s", new Object[]{target});
        this.options = (Options)Util.checkNotNull(options, "options for %s", new Object[]{target});
        this.propagationPolicy = propagationPolicy;
        if (forceDecoding) {
            this.decoder = decoder;
            this.asyncResponseHandler = null;
        } else {
            this.decoder = null;
            this.asyncResponseHandler = new AsyncResponseHandler(logLevel, logger, decoder, errorDecoder, decode404, closeAfterDecode);
        }

    }

    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;
                }
            }
        }
    }

    long elapsedTime(long start) {
        return TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
    }

    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);
    }

    Options findOptions(Object[] argv) {
        if (argv != null && argv.length != 0) {
            Stream var10000 = Stream.of(argv);
            Options.class.getClass();
            var10000 = var10000.filter(Options.class::isInstance);
            Options.class.getClass();
            return (Options)var10000.map(Options.class::cast).findFirst().orElse(this.options);
        } else {
            return this.options;
        }
    }

    static class Factory {
        private final Client client;
        private final Retryer retryer;
        private final List<RequestInterceptor> requestInterceptors;
        private final Logger logger;
        private final Level logLevel;
        private final boolean decode404;
        private final boolean closeAfterDecode;
        private final ExceptionPropagationPolicy propagationPolicy;
        private final boolean forceDecoding;

        Factory(Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors, Logger logger, Level logLevel, boolean decode404, boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy, boolean forceDecoding) {
            this.client = (Client)Util.checkNotNull(client, "client", new Object[0]);
            this.retryer = (Retryer)Util.checkNotNull(retryer, "retryer", new Object[0]);
            this.requestInterceptors = (List)Util.checkNotNull(requestInterceptors, "requestInterceptors", new Object[0]);
            this.logger = (Logger)Util.checkNotNull(logger, "logger", new Object[0]);
            this.logLevel = (Level)Util.checkNotNull(logLevel, "logLevel", new Object[0]);
            this.decode404 = decode404;
            this.closeAfterDecode = closeAfterDecode;
            this.propagationPolicy = propagationPolicy;
            this.forceDecoding = forceDecoding;
        }

        public MethodHandler create(Target<?> target, MethodMetadata md, feign.RequestTemplate.Factory buildTemplateFromArgs, Options options, Decoder decoder, ErrorDecoder errorDecoder) {
            return new SynchronousMethodHandler(target, this.client, this.retryer, this.requestInterceptors, this.logger, this.logLevel, md, buildTemplateFromArgs, options, decoder, errorDecoder, this.decode404, this.closeAfterDecode, this.propagationPolicy, this.forceDecoding);
        }
    }
}

远程调用时,构建了RequestInterceptor。

自定义feign拦截器

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;

/**
 * @description: TODO
 * @author: <a href="mailto:batis@foxmail.com">清风</a>
 * @date: 2022/3/10 23:03
 * @version: 1.0
 */
@Configuration
public class FamilyFegin {

    @Bean(name ="requestInterceptor")
    public RequestInterceptor requestInterceptor(){
        return new RequestInterceptor() {
            @Override
            public void apply(RequestTemplate requestTemplate) {
                //RequestContextHolder拿到刚请求来的数据
                ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = requestAttributes.getRequest();
                System.out.println("调用feign之前");
                //同步请求头数据
                String cookie = request.getHeader("Cookie");//老数据
                //给新请求同步老请求的cookie
                requestTemplate.header("Cookie", cookie);
            }
        };
    }
}

拦截器说明

RequestContextHolder.getRequestAttributes()获取到RequestAttributes类,RequestAttributes源码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.web.context.request;

import org.springframework.lang.Nullable;

public interface RequestAttributes {
    int SCOPE_REQUEST = 0;
    int SCOPE_SESSION = 1;
    String REFERENCE_REQUEST = "request";
    String REFERENCE_SESSION = "session";

    @Nullable
    Object getAttribute(String var1, int var2);

    void setAttribute(String var1, Object var2, int var3);

    void removeAttribute(String var1, int var2);

    String[] getAttributeNames(int var1);

    void registerDestructionCallback(String var1, Runnable var2, int var3);

    @Nullable
    Object resolveReference(String var1);

    String getSessionId();

    Object getSessionMutex();
}

ServletRequestAttributes继承了AbstractRequestAttributes,AbstractRequestAttributes实现了RequestAttributes,因此可以强转。


public abstract class AbstractRequestAttributes implements RequestAttributes {
    protected final Map<String, Runnable> requestDestructionCallbacks = new LinkedHashMap(8);
    private volatile boolean requestActive = true;

    public AbstractRequestAttributes() {
    }

    public void requestCompleted() {

注意:该处理是在同步一个线程种处理的,才能获取之前的heard中的cookie信息。异步多线程该处理方式不同。

3

评论 (0)

取消