Feign调用时将请求头信息传递到调用下游方案
一、需求分析
现有接口存在对用户信息进行拦截鉴权需求,在使用Feign包调用下游接口时,需要将当前请求头一直传递下去。
二、实现方案
在参考了网上的各种资料之后,通过自定义hystrix并发策略和Feign调用拦截器实现此需求
1、拦截器定义
拦截全部的Feign调用请求,从当前requestContext请求头中获取出需要的身份信息,再手动添加到requestTemplate中。
这里的问题是,当请求走到此拦截器中时,如果没有配置hystrix并发策略为信号量模式的话,就会根据hystrix默认的并发策略,进入一个新的线程池。所以在这里是获取不到我们想要的requestContext的。需要通过第二步进行处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | @Configuration public class FeignInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate requestTemplate) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder .getRequestAttributes(); // 服务内部跳转时,可能不存在Request上下文 if (Objects.isNull(attributes)){ requestTemplate.header(AuthorizationUtil.Authorization, AuthorizationUtil.Authorization); return ; } HttpServletRequest request = attributes.getRequest(); boolean hasParam=(request.getParameter(AuthorizationUtil.Authorization)!= null && ! "" .equals(request.getParameter(AuthorizationUtil.Authorization))); if ( "GET" .equals(request.getMethod())&& hasParam){ requestTemplate.header(AuthorizationUtil.Authorization, request.getParameter(AuthorizationUtil.Authorization)); return ; } Enumeration<String> headerNames = request.getHeaderNames(); boolean bool = false ; if (headerNames != null ) { while (headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String values = request.getHeader(name); // 只取需要的header if ( "Authorization" .equals(name) || "authorization" .equals(name)){ requestTemplate.header(name, values); bool = true ; } else if (AuthorizationUtil.Authorization.equals(name)) { requestTemplate.header(name, values); bool = true ; } } if (!bool) { //判断url中是否有数据 requestTemplate.header(AuthorizationUtil.Authorization, AuthorizationUtil.Authorization); } } else { requestTemplate.header(AuthorizationUtil.Authorization, AuthorizationUtil.Authorization); } } } |
2、自定义hystrix并发策略
重点在于继承HystrixConcurrencyStrategy之后,重写wrapCallable方法,内部把当前上下文中的信息填充到新线程的上下文中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | @Configuration public class RequestHeaderHystrixConcurrencyStrategy extends HystrixConcurrencyStrategy { private static final Log log = LogFactory.getLog(RequestHeaderHystrixConcurrencyStrategy. class ); private HystrixConcurrencyStrategy delegate; public RequestHeaderHystrixConcurrencyStrategy() { try { this .delegate = HystrixPlugins.getInstance().getConcurrencyStrategy(); if ( this .delegate instanceof RequestHeaderHystrixConcurrencyStrategy) { // 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(); } } } } |
3、Feign配置注册
如果是微服务项目,并且是通过引包的方式调用Feign接口的话,需要装配拦截器FeignInterceptor。
1 2 3 4 5 6 7 8 | @Configuration public class FeignSupportConfig { @Bean public RequestInterceptor requestInterceptor(){ return new FeignInterceptor(); } } |
在项目启动类上加@ComponentScan,配置FeignSupportConfig所在的包路径,使拦截器生效。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下