Feign调用丢失Header的解决方案
source link: http://mp.weixin.qq.com/s?__biz=MzI0NTYzMjM0Ng%3D%3D&%3Bmid=2247484515&%3Bidx=1&%3Bsn=a913a98fa53be30cfc5e6c15682eb7b9
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
问题
在 Spring Cloud 中 微服务之间的调用会用到Feign,但是在默认情况下,Feign 调用远程服务存在Header请求头丢失问题。
解决方案
首先需要写一个 Feign请求拦截器,通过实现RequestInterceptor接口,完成对所有的Feign请求,传递请求头和请求参数。
Feign 请求拦截器
public class FeignBasicAuthRequestInterceptor implements RequestInterceptor { private static final Logger logger = LoggerFactory.getLogger(FeignBasicAuthRequestInterceptor.class); @Override public void apply(RequestTemplate requestTemplate) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); Enumeration<String> headerNames = request.getHeaderNames(); if (headerNames != null) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String values = request.getHeader(name); requestTemplate.header(name, values); } } Enumeration<String> bodyNames = request.getParameterNames(); StringBuffer body =new StringBuffer(); if (bodyNames != null) { while (bodyNames.hasMoreElements()) { String name = bodyNames.nextElement(); String values = request.getParameter(name); body.append(name).append("=").append(values).append("&"); } } if(body.length()!=0) { body.deleteCharAt(body.length()-1); requestTemplate.body(body.toString()); logger.info("feign interceptor body:{}",body.toString()); } } }
配置 让所有 FeignClient
,使用 FeignBasicAuthRequestInterceptor
feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic requestInterceptors: com.leparts.config.FeignBasicAuthRequestInterceptor
也可以配置让 某个 FeignClient
使用这个 FeignBasicAuthRequestInterceptor
feign: client: config: xxxx: # 远程服务名 connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic requestInterceptors: com.leparts.config.FeignBasicAuthRequestInterceptor
经过测试,上面的解决方案可以正常的使用;但是出现了新的问题。
在转发Feign的请求头的时候, 如果开启了Hystrix, Hystrix的默认隔离策略是Thread(线程隔离策略), 因此转发拦截器内是无法获取到请求的请求头信息的。
可以修改默认隔离策略为信号量模式:
hystrix.command.default.execution.isolation.strategy=SEMAPHORE
但信号量模式不是官方推荐的隔离策略;另一个解决方法就是自定义Hystrix的隔离策略。
自定义策略
HystrixConcurrencyStrategy 是提供给开发者去自定义hystrix内部线程池及其队列,还提供了包装callable的方法,以及传递上下文变量的方法。所以可以继承了HystrixConcurrencyStrategy,用来实现了自己的并发策略。
@Component 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 instance = HystrixPlugins.getInstance(); instance.registerConcurrencyStrategy(this); instance.registerCommandExecutionHook(commandExecutionHook); instance.registerEventNotifier(eventNotifier); instance.registerMetricsPublisher(metricsPublisher); instance.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; 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(); } } } }
致此,Feign调用丢失请求头的问题就解决的了 。
参考
https://blog.csdn.net/zl1zl2zl3/article/details/79084368
https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.0.RC2/reference/html/
-- END --
每一个“ 在 看 ”,都是对我最大的肯定 !
Recommend
-
6
数据丢失防护(DLP)是企业信息安全团队工具包中日益流行的解决方案。然而,选择DLP系统的标准往往是模糊的,就像是购买防腐剂的清单一样。因此,他们会选择一个使用了更具侵入性的广告和承诺附加功能的品牌,并且所有这些都会带有一个吸引人的价格...
-
5
nginx做转发时,带下划线字段的header内容丢失零一间2021.06.10 11:09:57字数 255阅读 28 在日常的开发中,我们有时候会在http请求头...
-
2
Deliverer 1.1.2 修复使用魔术方法后调用栈丢失的问题非常高兴还是有不少朋友在使用这个项目的,从而帮助他们解决了一些线上的问题。如果你对线上一个项目运行逻辑不熟...
-
4
LocalDateTime Feign 调用序列化失败 ...
-
3
最近在学习如何使用springcloud,当学习到跨服务调用接口时接触到Feign和Ribbon,网上有
-
2
V2EX › 问与答 docker 容器化部署与 feign 服务调用问题
-
2
Sentinel整合Feign对远程调用限流并降级 推荐 原创 梁云亮 2022-10-14 11:15:48
-
6
在我们公司里,不同的服务之间通过Feign进行远程调用,但是,我们在尝试使调用可重试时遇到了一个小问题,Feign框架本身可以配置的自己的重试机制,但是它是一刀切的方式,所有的调用都是同样的机制,没有办法像我们希望的那样在每个方法...
-
3
Chatwoot Nignx 代理丢失 Header 信息 Posted on 04/17/2023 , Last modified on 04/17/2...
-
1
简化本地Feign调用,老手教你这么玩 作者:Dr Hydra 2023-06-09 13:56:42 本文提供了一个在本地开发过程中简化Feign调用的思路,相比之前需要麻烦的修改FeignClient中的url而言,能够节省不少的无效劳动,并且通过...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK