最近做一个项目,用到springCloud,结果遇到session丢失的问题,从zuul->feign->shiro->boot都有问题,默认情况下,zuul和feign在转发时都会丢掉header,于是花时间研究下。

转:https://blog.csdn.net/Crystalqy/article/details/79083857

自定义RequestInterceptor

使用Feign调用某个远程API,这个远程API需要传递一个鉴权信息,我们可以把cookie里面的session信息放到Header里面,这个Header是动态的,跟你的HttpRequest相关,我们选择编写一个拦截器来实现Header的传递,也就是需要实现RequestInterceptor接口,具体代码如下:

@Configuration

@EnableFeignClients(basePackages = "com.xxx.xxx.client")

public class FeignClientsConfigurationCustom implements RequestInterceptor {

@Override

public void apply(RequestTemplate template) {

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

if (requestAttributes == null) {

return;

}

HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

Enumeration headerNames = request.getHeaderNames();

if (headerNames != null) {

while (headerNames.hasMoreElements()) {

String name = headerNames.nextElement();

Enumeration values = request.getHeaders(name);

while (values.hasMoreElements()) {

String value = values.nextElement();

template.header(name, value);

}

}

}

}

}

经过测试,上面的解决方案可以正常的使用;

但是,当引入Hystrix熔断策略时,出现了一个新的问题:

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

获取不到request信息,从而无法传递session信息,最终发现RequestContextHolder.getRequestAttributes()该方法是从ThreadLocal变量里面取得对应信息的,这就找到问题原因了,由于Hystrix熔断机制导致的。

Hystrix有隔离策略:THREAD以及SEMAPHORE,当隔离策略为 THREAD 时,是没办法拿到 ThreadLocal 中的值的。

因此有两种解决方案:

方案一:调整格隔离策略

hystrix.command.default.execution.isolation.strategy: SEMAPHORE

这样配置后,Feign可以正常工作。

但该方案不是特别好。原因是Hystrix官方强烈建议使用THREAD作为隔离策略! 可以参考官方文档说明

方案二:自定义策略

记得之前在研究zipkin日志追踪的时候,看到过Sleuth有自己的熔断机制,用来在thread之间传递Trace信息,Sleuth是可以拿到自己上下文信息的,查看源码找到了

org.springframework.cloud.sleuth.instrument.hystrix.SleuthHystrixConcurrencyStrategy

这个类,查看SleuthHystrixConcurrencyStrategy的源码,继承了HystrixConcurrencyStrategy,用来实现了自己的并发策略。

/**

* Abstract class for defining different behavior or implementations for concurrency related aspects of the system with default implementations.

*

* For example, every {@link Callable} executed by {@link HystrixCommand} will call {@link #wrapCallable(Callable)} to give a chance for custom implementations to decorate the {@link Callable} with

* additional behavior.

*

* When you implement a concrete {@link HystrixConcurrencyStrategy}, you should make the strategy idempotent w.r.t ThreadLocals.

* Since the usage of threads by Hystrix is internal, Hystrix does not attempt to apply the strategy in an idempotent way.

* Instead, you should write your strategy to work idempotently. See https://github.com/Netflix/Hystrix/issues/351 for a more detailed discussion.

*

* See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins:

* href="https://github.com/Netflix/Hystrix/wiki/Plugins">https://github.com/Netflix/Hystrix/wiki/Plugins

.

*/

public abstract class HystrixConcurrencyStrategy

搜索发现有好几个地方继承HystrixConcurrencyStrategy类

image.png

其中就有我们熟悉的Spring Security和刚才提到的Sleuth都是使用了自定义的策略,同时由于Hystrix只允许有一个并发策略,因此为了不影响Spring Security和Sleuth,我们可以参考他们的策略实现自己的侧路,大致思路:

将现有的并发策略作为新并发策略的成员变量;

在新并发策略中,返回现有并发策略的线程池、Queue;

代码如下:

public class FeignHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy {

private static final Logger log = LoggerFactory.getLogger(FeignHystrixConcurrencyStrategy.class);

private HystrixConcurrencyStrategy delegate;

public FeignHystrixConcurrencyStrategy() {

try {

this.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();

if (this.delegate instanceof FeignHystrixConcurrencyStrategy) {

// 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 Callable wrapCallable(Callable callable) {

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();

return new WrappedCallable<>(callable, requestAttributes);

}

@Override

public ThreadPoolExecutor getThreadPool(HystrixThreadPoolKey threadPoolKey,

HystrixProperty corePoolSize, HystrixProperty maximumPoolSize,

HystrixProperty keepAliveTime, TimeUnit unit, BlockingQueue 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 getBlockingQueue(int maxQueueSize) {

return this.delegate.getBlockingQueue(maxQueueSize);

}

@Override

public HystrixRequestVariable getRequestVariable(HystrixRequestVariableLifecycle rv) {

return this.delegate.getRequestVariable(rv);

}

static class WrappedCallable implements Callable {

private final Callable target;

private final RequestAttributes requestAttributes;

public WrappedCallable(Callable 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();

}

}

}

}

至此,结合FeignClientsConfigurationCustom配置feign调用session丢失的问题完美解决。

feign session 调用_Feign调用session丢失解决方案相关推荐

  1. 爱上MVC~ajax调用分部视图session超时页面跳转问题

    这个问题出现了很多年了,都没有解决,问题是这样的,有一个需要授权才可以访问的分部视图,在一个view中使用ajax的方法去调用它,然后更新页面的局部DIV,这时,如果你长时间不操作,session会超 ...

  2. Spring Session - Cookie VS Session VS Token 以及 Session不一致问题的N种解决方案

    文章目录 Cookie VS Session VS Token History Cookie Session Token Session不一致问题 Session不一致解决方案 nginx sessi ...

  3. Session跨域及单点登录解决方案

    cookie机制 关于cookie和seesion的联系 cookie中会包含那些信息 名字,值,过期时间,路径,域 cookie会带到http请求头中发送给服务端 如果cookie没有设置过期时间的 ...

  4. SpringCloud Feign声明式服务调用

    SpringCloud Feign声明式服务调用 1. 加入pom依赖 2. Application.java上声明@EnableFeignClients 3. @FeignClient声明接口调用服 ...

  5. SpringCloud服务消费者第一次调用出现超时问题的解决方案

    SpringCloud服务消费者第一次调用出现超时问题的解决方案 参考文章: (1)SpringCloud服务消费者第一次调用出现超时问题的解决方案 (2)https://www.cnblogs.co ...

  6. Spring Security——集成Spring Session、Redis和JSON序列化解决方案

    官方文档 https://docs.spring.io/spring-session/docs/2.4.2/reference/html5/#spring-security Maven 主要 < ...

  7. ASP Session的功能的缺陷以及解决方案

    ASP Session的功能的缺陷以及解决方案 参考文章: (1)ASP Session的功能的缺陷以及解决方案 (2)https://www.cnblogs.com/aguan/p/4014721. ...

  8. c# 调用cmd WaitForExit 死锁问题解决方案

    c# 调用cmd WaitForExit 死锁问题解决方案 参考文章: (1)c# 调用cmd WaitForExit 死锁问题解决方案 (2)https://www.cnblogs.com/brad ...

  9. 微服务调用失败的一种解决方案

    一.简介 今天微服务和远程调用已经使用的很广泛了,可以解决我们很多的问题,不过由于远程调用不可控因素更多,失败的可能性更大,但是一些接口可能需要很高的要求,需要每一次调用都需要成功.比如订单流转.调用 ...

  10. 关于Python user32.dll SetWindowPos调用无效的问题的解决方案

    关于Python user32.dll SetWindowPos调用无效的问题的解决方案 我刚开始时使用了以下代码,但调用无效 # -*- coding: utf-8 -*- import ctype ...

最新文章

  1. Djando 的 cmd命令
  2. 宅久伤身?最新研究:独居让免疫系统变强了,但阿尔兹海默风险也变高了
  3. groovy 兼容 java,升级Groovy 1.7 - 2.1不兼容
  4. SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions
  5. python调用sdk的文章_如何使用 python 接入虹软 ArcFace SDK
  6. 爬虫python怎么下载_在网上下了一个 python 爬虫程序,怎么运行?
  7. 【高并发】JUC中的循环栅栏CyclicBarrier的6种使用场景
  8. Open3d之内部形状描述子ISS
  9. python自动化测试-简单实现接口自动化测试(基于python)
  10. Nagios的安装与配置并实现飞信报警
  11. Spring Boot ES 实战,直接拿来用!
  12. 云南省人口密度格网数据
  13. Java常用实现八种排序算法与代码实现
  14. 基于ssm的简单员工信息管理系统
  15. android 设置组件背景图片,Android TextView背景颜色与背景图片设置
  16. python身份证号码校验
  17. 新兴新能源设施[1]--盐穴压缩空气储能相关配套设施
  18. 中远通在创业板IPO过会:前三季度收入11亿元,罗厚斌为董事长
  19. android实现对PDF进行签名、涂鸦操作
  20. 【视频学习】12堂快速阅读课,10倍提升阅读效率

热门文章

  1. 怎样在html应用样式表,html – 如何仅将CSS样式应用于文本
  2. wordpress 关于裁剪图片错误问题
  3. 汇编语言相关图书推荐
  4. Win7环境下VS2010配置Cocos2d-x-2.1.4最新版本号的开发环境
  5. SQL注射技术总结文档
  6. Linux上安装GCC编译器过程实录
  7. c语言如何交替打印大小写字母,C/C++语言实现两个线程交替打印奇偶数
  8. ElasticSearch全文搜索引擎之Restful API和索引操作篇
  9. Spring Cloud Alibaba Sentinel之流控规则篇
  10. Breakpad Native异常捕获