千家信息网

如何使用Feign动态设置header

发表于:2025-02-16 作者:千家信息网编辑
千家信息网最后更新 2025年02月16日,今天小编给大家分享一下如何使用Feign动态设置header的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面
千家信息网最后更新 2025年02月16日如何使用Feign动态设置header

今天小编给大家分享一下如何使用Feign动态设置header的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

Feign动态设置header和原理

项目中用到了Feign做远程调用, 有部分场景需要动态配置header

开始的做法是通过 @RequestHeader 设置参数来实现动态的header配置

例如

@GetMapping(value = "/test", consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})    String access(@RequestHeader("Auth") String auth, @RequestBody Expression expression);

这种方式虽然可以达到header的动态配置, 但是当参数过多时会降低接口可用性, 所以想通过传递bean的方式来设置header

先说解决办法

public class HeaderInterceptor implements RequestInterceptor {    @Override    public void apply(RequestTemplate requestTemplate) {        byte[] bytes = requestTemplate.requestBody().asBytes();        Identity identity = JSONObject.parseObject(bytes, Identity.class);        requestTemplate.header("Auth", identity.getSecret());    }} /** * configuration指定Interceptor**/@FeignClient(name = "test", url = "127.0.0.1:8300", configuration = HeaderInterceptor.class)public interface GolangTestHandle2 {    @GetMapping(value = "/handler", consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE})    String handle(Identity identity);}

自定义Interceptor实现RequestInterceptor接口, 回调方法apply提供了RequestTemplate对象, 对象内部封装了request的所有信息, 最后通过configuration指定接口, 之后就随便你怎么玩了(例如通过body获取接口参数并动态设置header)

值得注意的一点是HeaderInterceptor如果注入到Springboot容器的话会全局生效, 就是说及时没有指定configuration也会对全局feign接口生效, 为什么呢? 这里简单说明一下

首先Feign为每个feign class创建springcontext上下文

spring通过调用getObject获取feign工厂实例

    @Override    public Object getObject() throws Exception {        return getTarget();    }

内部调用FeignClientFatoryBean.getTarget()方法

 T getTarget() {        //获取feign上下文        FeignContext context = this.applicationContext.getBean(FeignContext.class);        //构建feign Builder        Feign.Builder builder = feign(context);        ...    }

根据feign(FeignContext context)构建Builder

protected Feign.Builder feign(FeignContext context) {        FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);        Logger logger = loggerFactory.create(this.type);        // @formatter:off        Feign.Builder builder = get(context, Feign.Builder.class)                // required values                .logger(logger)                //默认springEncoder                .encoder(get(context, Encoder.class))                //默认OptionalDecoder                .decoder(get(context, Decoder.class))                //默认SpringMvcContrat                .contract(get(context, Contract.class));        // @formatter:on        //配置该feign的context        configureFeign(context, builder);        return builder;    }

在构建过程中通过FeignClientFactoryBean.configureUsingConfiguration为feign class注册基本的配置项, 其中也包括了Interceptor的注册

    protected void configureUsingConfiguration(FeignContext context,            Feign.Builder builder) {        Logger.Level level = getOptional(context, Logger.Level.class);        if (level != null) {            builder.logLevel(level);        }        Retryer retryer = getOptional(context, Retryer.class);        if (retryer != null) {            builder.retryer(retryer);        }        ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);        if (errorDecoder != null) {            builder.errorDecoder(errorDecoder);        }        Request.Options options = getOptional(context, Request.Options.class);        if (options != null) {            builder.options(options);        }        //从feign context获取interceptors        Map requestInterceptors = context                .getInstances(this.contextId, RequestInterceptor.class);        if (requestInterceptors != null) {            builder.requestInterceptors(requestInterceptors.values());        }        if (this.decode404) {            builder.decode404();        }    }

contextId为具体的feign class id, RequestInterceptor为具体的接口, 即是说通过context.getInstances获取所有RequestInterceptor实例并注册到builder中.

    public  Map getInstances(String name, Class type) {        AnnotationConfigApplicationContext context = getContext(name);        //使用beanNamesForTypeIncludingAncestors        if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context,                type).length > 0) {            return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);        }        return null;    }

获取工厂中的实例使用的是beanNamesForTypeIncludingAncestors方法, 该方法不仅会从feign的factory中查找, 也会通过父级别spring工厂查找相应实例(类似于springmvc的工厂)

也是因为该方法, 即使你没有在FeignClient中配置configuration, 但是你的Interceptor通过@Component等方法注入容器的话也会全局生效的, 所以如果指向让你的Interceptor部分生效不让它注入到Spring容器就好

设置Feign的header信息(两种形式)

在使用微服务SpringCloud全家桶组件Fegin的时候,我们在进行远程服务之间调用的同时,为了防止客户端劫持信息,我们需要将一些敏感信息添加到我们的Fegin头部(Header)当中,今天朋友问起,总结一下:那么工作中常见的方式有两种

1.在方法参数前面添加@RequestHeader注解

@PostMapping(value = "/getPersonDetail") public ServerResponse getPersonDetail(@RequestBody Map map,@RequestHeader(name = "id") String id);

使用@RequestHeader(name = "id")可以传递动态header属性

2.实现RequestInterceptor接口

设置Header(所有的Fegin请求)

import org.springframework.context.annotation.Configuration; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import feign.RequestInterceptor; import feign.RequestTemplate; @Configuration public class FeignConfiguration implements RequestInterceptor {            @Override            public void apply(RequestTemplate template) {                      ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();                       HttpServletRequest request = attributes.getRequest();                        Enumeration headerNames = request.getHeaderNames();                        if (headerNames != null) {                                    while (headerNames.hasMoreElements()) {                                             String name = headerNames.nextElement();                                              String values = request.getHeader(name);                                             template.header(name, values);                                    }                            }            } }  @Component@FeignClient(value = "abc",fallback = abcServiceHystric.class ,configuration = FeignConfiguration.class) public interface AbcService { }

以上就是"如何使用Feign动态设置header"这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。

动态 接口 方法 配置 信息 参数 实例 工厂 知识 篇文章 全局 容器 方式 上下 上下文 内容 对象 就是 部分 服务 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 有源植入物网络安全 计算机考试网络安全素质教育 腾讯云服务器怎么转变为wifi 身份证号数据库数据类型 福州软件开发公司有哪些 数据库软件有flash吗 饥荒服务器跳世界保存 sybase数据库导出 移动服务器密码原始密码是多少 郑州鸠鸠科技互联网公司 浙江网络技术咨询值得推荐 软件开发模型说课 数据库重要的知识点 安徽电商软件开发价钱 软件开发中心高级经理戴岩 数据库属性的文件选项功能 徐汇区银联网络技术推荐咨询 开源软件开发要多少钱 什么是嵌入式web服务器 基因组数据库的定义及功能 软件连接不上SQL数据库 微软服务器数据会被窃取吗 新乡星易网络技术有限公司 堆赢互联网信息科技 影响我国的网络安全的 2019网络安全宣传语 新手学习网络安全 北京航天航空大学网络安全学院 网络技术服务包括游戏吗 如皋口碑好的网络技术诚信经营
0