欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Feign调用服务Session失效问题以及使用RequestContextHolder.getRequestAttributes()获取值为null的问题

程序员文章站 2022-06-28 17:50:28
文章目录一、Feign调用服务Session失效问题二、RequestContextHolder.getRequestAttributes()获取值为null解决方式一 关闭Fegin的熔断解决方式二 调整隔离策略解决方式三 自定义并发策略一、Feign调用服务Session失效问题微服务使用feign相互之间调用时,存在session丢失的问题。例如,使用Feign调用某个远程API,这个远程API需要传递一个鉴权信息,我们可以把cookie里面的session信息放到Header里面,我们需要编写...

一、Feign调用服务Session失效问题

微服务使用feign相互之间调用时,存在session丢失的问题。例如,使用Feign调用某个远程API,这个远程API需要传递一个鉴权信息,我们可以把cookie里面的session信息放到Header里面,我们需要编写一个拦截器来实现Header的传递,需要实现RequestInterceptor接口

package com.lsh.intercepter;

import com.lsh.config.RequestAttributeHystrixConcurrencyStrategy;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.openfeign.EnableFeignClients;
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;
import java.util.Enumeration;

/**
 * @author :LiuShihao
 * @date :Created in 2020/11/12 9:29 上午
 * @desc : 实现RequestInterceptor,用于设置feign全局请求模板
 *
 * 需要一个或者多个RequestInterceptor去配置诸如请求头信息,还给出了授权的头部配置。
 * 到这里我们就明白了,我们需要实现一个RequestInterceptor,在里面将原来的请求头信息付给下游请求,实际上就是Cookie信息,
 * 这样sessionId就传到下游了,也就实现了共享。
 */

@Configuration
@EnableFeignClients(basePackages = "com.lsh.service")
public class FeignRequestIntercepter implements RequestInterceptor {

    @Autowired
    RequestAttributeHystrixConcurrencyStrategy  requestAttributeHystrixConcurrencyStrategy;
    @Override
    public void apply(RequestTemplate requestTemplate) {
        /**
         * 使用 RequestContextHolder.getRequestAttributes() 静态方法获得Request。 (但仅限于Feign不开启Hystrix支持时。)
         * 当Feign开启Hystrix支持时,获取值为null
         * 原因在于,Hystrix的默认隔离策略是THREAD 。而 RequestContextHolder 源码中,使用了两个ThreadLocal 。
         * 解决方案一:调整隔离策略 将隔离策略设为SEMAPHORE即可
         * hystrix.command.default.execution.isolation.strategy: SEMAPHORE
         * 这样配置后,Feign可以正常工作。但该方案不是特别好。原因是Hystrix官方强烈建议使用THREAD作为隔离策略!
         *
         * 解决方案二:自定义并发策略
         * 既然Hystrix不太建议使用SEMAPHORE作为隔离策略,那么是否有其他方案呢?
         * 答案是自定义并发策略,目前,Spring Cloud Sleuth以及Spring Security都通过该方式传递 ThreadLocal 对象。
         * 编写自定义并发策略比较简单,只需编写一个类,让其继承HystrixConcurrencyStrategy ,并重写wrapCallable 方法即可。
         *
         */
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes == null){
            System.out.println("requestAttributes为null");
            return;
        }
        //获取本地线程绑定的请求对象
        HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
        System.out.println("获取本地线程绑定的请求对象:"+request);
        //给请求模板附加本地线程头部信息,主要是cookie信息
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()){
            String name =(String) headerNames.nextElement();
            System.out.println("name:"+name);
            requestTemplate.header(name,request.getHeader(name));
        }
    }
}

二、RequestContextHolder.getRequestAttributes()获取值为null

解决方式一 关闭Fegin的熔断

需要关闭Fegin的熔断。
Feign调用服务Session失效问题以及使用RequestContextHolder.getRequestAttributes()获取值为null的问题
Feign调用服务Session失效问题以及使用RequestContextHolder.getRequestAttributes()获取值为null的问题

解决方式二 调整隔离策略

方式一仅限于Feign不开启Hystrix支持时,当Feign开启Hystrix支持时,获取值为null。
所以将隔离策略设为SEMAPHORE即可。

hystrix.command.default.execution.isolation.strategy: SEMAPHORE
但是:这样配置后,Feign可以正常工作。但该方案不是特别好。原因是Hystrix官方强烈建议使用THREAD作为隔离策略!
yml配置

feign:
  hystrix:
    enabled: false
# 如果idea不识别hystrix.command...这个配置    是因为没有加入到Spring管理容器,不影响使用
hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: SEMAPHORE

解决方式三 自定义并发策略

目前,Spring Cloud Sleuth以及Spring Security都通过这种方式传递 ThreadLocal 对象。
编写自定义并发策略比较简单,只需编写一个类,让其继承HystrixConcurrencyStrategy ,并重写wrapCallable 方法即可。
Feign调用服务Session失效问题以及使用RequestContextHolder.getRequestAttributes()获取值为null的问题
完整代码:

package com.lsh.config;

import com.netflix.hystrix.HystrixThreadPoolKey;
import com.netflix.hystrix.HystrixThreadPoolProperties;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariable;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestVariableLifecycle;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
import com.netflix.hystrix.strategy.executionhook.HystrixCommandExecutionHook;
import com.netflix.hystrix.strategy.metrics.HystrixMetricsPublisher;
import com.netflix.hystrix.strategy.properties.HystrixPropertiesStrategy;
import com.netflix.hystrix.strategy.properties.HystrixProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author :LiuShihao
 * @date :Created in 2020/11/12 10:56 上午
 * @desc :自定义并发策略
 * 参考文章:http://www.itmuch.com/spring-cloud-sum/hystrix-threadlocal/
 */
@Slf4j
@Component
public class RequestAttributeHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

    private HystrixConcurrencyStrategy delegate;

    public RequestAttributeHystrixConcurrencyStrategy() {
        try {
            log.info("加载RequestAttributeHystrixConcurrencyStrategy");
            this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
            if (this.delegate instanceof RequestAttributeHystrixConcurrencyStrategy) {
                // 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 ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,
                                            HystrixThreadPoolProperties threadPoolProperties) {
        return this.delegate.getThreadPool(threadPoolKey, threadPoolProperties);
    }

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

本文地址:https://blog.csdn.net/DreamsArchitects/article/details/109642312