feign调用session丢失解决方案
最近在做项目的时候发现,微服务使用feign相互之间调用时,存在session丢失的问题。例如,使用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<String> headerNames = request.getHeaderNames(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); Enumeration<String> values = request.getHeaders(name); while (values.hasMoreElements()) { String value = values.nextElement(); template.header(name, value); } } } } }
经过测试,上面的解决方案可以正常的使用;
但是,当引入Hystrix熔断策略时,出现了一个新的问题:
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
此时requestAttributes会返回null,从而无法传递session信息,最终发现RequestContextHolder.getRequestAttributes(),该方法是从ThreadLocal变量里面取得对应信息的,这就找到问题原因了,是由于Hystrix熔断机制导致的。
Hystrix有2个隔离策略: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.* <p>* 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.* <p>* 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.* <p>* See {@link HystrixPlugins} or the Hystrix GitHub Wiki for information on configuring plugins: <a* href="https://github.com/Netflix/Hystrix/wiki/Plugins">https://github.com/Netflix/Hystrix/wiki/Plugins</a>.*/
public abstract class HystrixConcurrencyStrategy
搜索发现有好几个地方继承了HystrixConcurrencyStrategy类
其中就有我们熟悉的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 <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(); } } }
}
最后,将这个策略类作为bean配置到feign的配置类FeignClientsConfigurationCustom中
@Beanpublic FeignHystrixConcurrencyStrategy feignHystrixConcurrencyStrategy() {return new FeignHystrixConcurrencyStrategy();}
至此,结合FeignClientsConfigurationCustom配置feign调用session丢失的问题完美解决。
feign调用session丢失解决方案相关推荐
- feign session 调用_springboot使用feign调用session传递失效解决方案
标题 框架 version 1 springboot 1.5.9.release 2 springCloud 1.2.4.release 3 eureka 1.6.2 4 feign 9.5.0 前言 ...
- SpringCloud 各个微服务之间会话共享以及Feign调用会话共享
目录 1.会话共享应用背景 2.SpringCloud各个微服务 (SpringBoot)应用之间会话共享 2.1.启动类或者Redis配置类加入Redis会话共享注解 2.2.配置Redis基本配置 ...
- 关于feign调用时,session丢失的解决方案
最近在做公司微服务项目的时候发现,微服务使用feign相互之间调用时,存在session丢失的问题. 例如,使用feign调用某个远程API,这个远程API需要传递一个鉴权信息,我们可以把cookie ...
- [转]ASP.NET 状态服务 及 session丢失问题解决方案总结
转自[http://blog.csdn.net/high_mount/archive/2007/05/09/1601854.aspx] 最近在开发一ASP.NET2.0系统时,在程序中做删除或创建文件 ...
- 【转】jquery文件上传插件uploadify在.NET中session丢失的解决方案
2019独角兽企业重金招聘Python工程师标准>>> 基于jQuery和Flash的多文件上传插件uploadify的确很好用,具体配置和使用方法见以前的一篇文章: <一款基 ...
- 使用restTemplate进行feign调用new HttpEntity<>报错解决方案
使用restTemplate进行feign调用new HttpEntity<>报错解决方案 问题背景 HttpEntity<>标红解决方案 心得 Lyric: 沙漠之中怎么会有 ...
- ASP.NET Session丢失问题原因及解决方案[转]
不得不老调重弹 正常操作情况下会有ASP.NET Session丢失的情况出现.因为程序是在不停的被操作,排除Session超时的可能.另外,Session超时时间被设定成60分钟,不会这么快就超时的 ...
- session丢失原因 java_Session丢失原因与解决方案
win2003 server下的IIS6默认设置下对每个运行在默认应用池中的工作者进程都会经过20多个小时后自动回收该进程, 造成保存在该进程中的session丢失. 因为Session,Applic ...
- 模式窗口window.open造成Session丢失的解决方法
从 HTML 模式或无模式对话框可能没有打开同一进程中 InternetExplorer 窗口中打开,因此模式窗口中调用 window.open()方法打开具体页面,可能造成session 丢失.例如 ...
最新文章
- 数据分析师必看:5大概率分布,你了解多少?
- python学习音频-详解python播放音频的三种方法
- 怎么写redmine wiki
- 错误日志这样排查,干活更得劲了!!
- c语言字符串加减_C语言中指针的介绍
- Java并发控制基础篇 Thread继承类和Runnable实现类
- [新思路]Online DVD Rental! 美国在线DVD租赁
- jQuery : ddSlick 自定义select下拉框 custom drop down with images and description.
- ios 学习札记 细节(四)
- cascader回显
- 实验2 线性表的链式存储结构的实现及其应用
- 一个完整的软件开发过程到底需要哪些步骤?
- Legion使用:半自动化网络渗透工具
- echarts 简单词云制作,自定义图案词云echarts-wordcloud.js
- HDU 2246 考研路茫茫——考试大纲
- URL重定向(跳转)漏洞
- B 站,真香 ! ! !
- php网页增加音乐代码,js给网页加上背景音乐及选择音效的方法
- AtCoder Grand Round 012B Splatter Painting
- Cybersecurity Challenges In The Uptake Of Artifitial Intelligence in Autonomous Driving [1]