解決SpringCloud使用Feign跨服調用時header請求頭中的信息丟失

在使用SpringCloud進行Feign跨服調用時header請求頭中的信息會丟失,是由於Feign是不會帶上當前請求的Cookie信息和頭信息的,這個時候就須要重寫請求攔截。網絡

一、須要重寫RequestInterceptor接口中的apply方法(前提是Feign的隔離策略爲SEMAPHORE)併發

@Component
public class FeignInterceptor implements RequestInterceptor{

    @Override
    public void apply(RequestTemplate template) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
           //將token信息放入header中
            template.header("access_token",request.getHeader("access_token"));
        }
    }
}    

注意當Feign的隔離策略爲THREAD,因爲當使用該隔離策略時,是沒辦法拿到 ThreadLocal 中的值的,可是RequestContextHolder 源碼中,使用了兩個ThreadLocal,所以當使用該隔離策略時是沒有辦法經過RequestContextHolder獲取到request對象的,這時若是你還堅持使用THREAD這個隔離策略就須要自定義策略(重寫THREAD隔離策略),代碼以下:app

/**
 * 自定義併發策略
 * 將現有的併發策略做爲新併發策略的成員變量
 * 在新併發策略中,返回現有併發策略的線程池、Queue
 *
 * hystrix.command.default.execution.isolation.strategy=THREAD   Hystrix的默認隔離策略(官方推薦,當使用該隔離策略時,是沒辦法拿到 ThreadLocal 中的值的,可是
 *                                                               RequestContextHolder 源碼中,使用了兩個ThreadLocal)
 * hystrix.command.default.execution.isolation.strategy=SEMAPHORE (將隔離策略改成SEMAPHORE 也能夠解決這個問題,可是官方並不推薦這個策略,由於這個策略對網絡資源消耗比較大)
 *
 * 主要是解決當 Hystrix的默認隔離策略是THREAD時,不能經過RequestContextHolder獲取到request對象的問題
 *
 * Create By yxl on 2018/5/22
 */
@Component
public class FeignConfig extends HystrixConcurrencyStrategy {
    private static final Logger log = LoggerFactory.getLogger(FeignConfig.class);
    private HystrixConcurrencyStrategy delegate;

    public FeignConfig() {
        try {
            this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.delegate instanceof FeignConfig) {
                // Welcome to singleton hell...
                return;
            }
            HystrixCommandExecutionHook commandExecutionHook =
                    HystrixPlugins.getInstance().getCommandExecutionHook();
            HystrixEventNotifier eventNotifier = HystrixPlugins.getInstance().getEventNotifier();
            HystrixMetricsPublisher metricsPublisher = HystrixPlugins.getInstance().getMetricsPublisher();
            HystrixPropertiesStrategy propertiesStrategy =
                    HystrixPlugins.getInstance().getPropertiesStrategy();
            this.logCurrentStateOfHystrixPlugins(eventNotifier, metricsPublisher, propertiesStrategy);
            HystrixPlugins.reset();
            HystrixPlugins.getInstance().registerConcurrencyStrategy(this);
            HystrixPlugins.getInstance().registerCommandExecutionHook(commandExecutionHook);
            HystrixPlugins.getInstance().registerEventNotifier(eventNotifier);
            HystrixPlugins.getInstance().registerMetricsPublisher(metricsPublisher);
            HystrixPlugins.getInstance().registerPropertiesStrategy(propertiesStrategy);
        } catch (Exception e) {
            log.error("Failed to register Sleuth Hystrix Concurrency Strategy", e);
        }
    }

    private void logCurrentStateOfHystrixPlugins(HystrixEventNotifier eventNotifier,
                                                 HystrixMetricsPublisher metricsPublisher, HystrixPropertiesStrategy propertiesStrategy) {
        if (log.isDebugEnabled()) {
            log.debug("Current Hystrix plugins configuration is [" + "concurrencyStrategy ["
                    + this.delegate + "]," + "eventNotifier [" + eventNotifier + "]," + "metricPublisher ["
                    + metricsPublisher + "]," + "propertiesStrategy [" + propertiesStrategy + "]," + "]");
            log.debug("Registering Sleuth Hystrix Concurrency Strategy.");
        }
    }

    @Override
    public <T> Callable<T> wrapCallable(Callable<T> callable) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        return new WrappedCallable<>(callable, requestAttributes);
    }

    @Override
    public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixProperty<Integer> corePoolSize, HystrixProperty<Integer> maximumPoolSize,
                                            HystrixProperty<Integer> keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        return this.delegate.getThreadPool(threadPoolKey, corePoolSize, maximumPoolSize, keepAliveTime,
                unit, workQueue);
    }

    @Override
    public BlockingQueue<Runnable> getBlockingQueue(int maxQueueSize) {
        return this.delegate.getBlockingQueue(maxQueueSize);
    }

    @Override
    public <T> HystrixRequestVariable<T> getRequestVariable(HystrixRequestVariableLifecycle<T> rv) {
        return this.delegate.getRequestVariable(rv);
    }

    static class WrappedCallable<T> implements Callable<T> {
        private final Callable<T> target;
        private final RequestAttributes requestAttributes;

        public WrappedCallable(Callable<T> target, RequestAttributes requestAttributes) {
            this.target = target;
            this.requestAttributes = requestAttributes;
        }

        @Override
        public T call() throws Exception {
            try {
                RequestContextHolder.setRequestAttributes(requestAttributes);
                return target.call();
            } finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }
    }
}
相關文章
相關標籤/搜索