feign session 调用_Feign调用session丢失解决方案
最近做一个项目,用到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丢失解决方案相关推荐
- 爱上MVC~ajax调用分部视图session超时页面跳转问题
这个问题出现了很多年了,都没有解决,问题是这样的,有一个需要授权才可以访问的分部视图,在一个view中使用ajax的方法去调用它,然后更新页面的局部DIV,这时,如果你长时间不操作,session会超 ...
- Spring Session - Cookie VS Session VS Token 以及 Session不一致问题的N种解决方案
文章目录 Cookie VS Session VS Token History Cookie Session Token Session不一致问题 Session不一致解决方案 nginx sessi ...
- Session跨域及单点登录解决方案
cookie机制 关于cookie和seesion的联系 cookie中会包含那些信息 名字,值,过期时间,路径,域 cookie会带到http请求头中发送给服务端 如果cookie没有设置过期时间的 ...
- SpringCloud Feign声明式服务调用
SpringCloud Feign声明式服务调用 1. 加入pom依赖 2. Application.java上声明@EnableFeignClients 3. @FeignClient声明接口调用服 ...
- SpringCloud服务消费者第一次调用出现超时问题的解决方案
SpringCloud服务消费者第一次调用出现超时问题的解决方案 参考文章: (1)SpringCloud服务消费者第一次调用出现超时问题的解决方案 (2)https://www.cnblogs.co ...
- Spring Security——集成Spring Session、Redis和JSON序列化解决方案
官方文档 https://docs.spring.io/spring-session/docs/2.4.2/reference/html5/#spring-security Maven 主要 < ...
- ASP Session的功能的缺陷以及解决方案
ASP Session的功能的缺陷以及解决方案 参考文章: (1)ASP Session的功能的缺陷以及解决方案 (2)https://www.cnblogs.com/aguan/p/4014721. ...
- c# 调用cmd WaitForExit 死锁问题解决方案
c# 调用cmd WaitForExit 死锁问题解决方案 参考文章: (1)c# 调用cmd WaitForExit 死锁问题解决方案 (2)https://www.cnblogs.com/brad ...
- 微服务调用失败的一种解决方案
一.简介 今天微服务和远程调用已经使用的很广泛了,可以解决我们很多的问题,不过由于远程调用不可控因素更多,失败的可能性更大,但是一些接口可能需要很高的要求,需要每一次调用都需要成功.比如订单流转.调用 ...
- 关于Python user32.dll SetWindowPos调用无效的问题的解决方案
关于Python user32.dll SetWindowPos调用无效的问题的解决方案 我刚开始时使用了以下代码,但调用无效 # -*- coding: utf-8 -*- import ctype ...
最新文章
- Djando 的 cmd命令
- 宅久伤身?最新研究:独居让免疫系统变强了,但阿尔兹海默风险也变高了
- groovy 兼容 java,升级Groovy 1.7 - 2.1不兼容
- SQL Server Window Function 窗体函数读书笔记二 - A Detailed Look at Window Functions
- python调用sdk的文章_如何使用 python 接入虹软 ArcFace SDK
- 爬虫python怎么下载_在网上下了一个 python 爬虫程序,怎么运行?
- 【高并发】JUC中的循环栅栏CyclicBarrier的6种使用场景
- Open3d之内部形状描述子ISS
- python自动化测试-简单实现接口自动化测试(基于python)
- Nagios的安装与配置并实现飞信报警
- Spring Boot ES 实战,直接拿来用!
- 云南省人口密度格网数据
- Java常用实现八种排序算法与代码实现
- 基于ssm的简单员工信息管理系统
- android 设置组件背景图片,Android TextView背景颜色与背景图片设置
- python身份证号码校验
- 新兴新能源设施[1]--盐穴压缩空气储能相关配套设施
- 中远通在创业板IPO过会:前三季度收入11亿元,罗厚斌为董事长
- android实现对PDF进行签名、涂鸦操作
- 【视频学习】12堂快速阅读课,10倍提升阅读效率
热门文章
- 怎样在html应用样式表,html – 如何仅将CSS样式应用于文本
- wordpress 关于裁剪图片错误问题
- 汇编语言相关图书推荐
- Win7环境下VS2010配置Cocos2d-x-2.1.4最新版本号的开发环境
- SQL注射技术总结文档
- Linux上安装GCC编译器过程实录
- c语言如何交替打印大小写字母,C/C++语言实现两个线程交替打印奇偶数
- ElasticSearch全文搜索引擎之Restful API和索引操作篇
- Spring Cloud Alibaba Sentinel之流控规则篇
- Breakpad Native异常捕获