Spring Cloud Feign 自定义配置(重试、拦截与错误码处理) 实践

人在魔都,目前为贝壳做事,本篇文章主要分享下 Feign 自定义配置的工程实践,希望你们可以找到些有用的东西,文章已被公众号收录

基于 spring-boot-starter-parent 2.1.9.RELEASE, spring-cloud-openfeign 2.1.3.RELEASE

引子

Feign 是一个声明式、模板化的HTTP客户端,简化了系统发起Http请求。创建它时,只需要创建一个接口,然后加上FeignClient注解,使用它时,就像调用本地方法一样,作为开发者的我们完全感知不到这是在调用远程的方法,也感知不到背后发起了HTTP请求:

/**
* @author axin
* @suammry xx 客户端
*/
@FeignClient(value = "xxClient",url = "${xx.host:www.axin.com}")
public interface DemoClient { @PostMapping(value = "/xxx/url", headers = "Content-Type=application/json"})
yourResponse requestHTTP(@RequestBody JSONObject param); }

上述的代码就是一个定义一个Feign HTTP 客户端,在其他类中只需要 @Autowired DemoClient,就可以像调用本地方法一样发起HTTP请求。

介绍就到这,接下来进入主题,因为 FeignClient 将发起HTTP请求与解析返回报文都做了包装,如果你的业务场景需要定制一些调用机制,比如:

  1. 我想在发起请求响应超时失败时自动重试 —— 自定义重试机制
  2. 我想单独对某些异常的HTTP状态码特殊处理 —— 自定义ErrorDecoder
  3. 服务端接口需要验证签名,所以我方在发起请求时要生成签名然后传过去 —— 定义 Fegin 拦截器

基于此,本文就以上述3个需求场景为例来介绍如何自定义 FeignClient 的配置

FeignClient的默认配置类

Feign Client 默认的配置类为 FeignClientsConfiguration, 这个类在 spring-cloud-netflix-core 的 jar 包下。

默认注入了很多 Feign 相关的配置Bean,包括FeignRetryer、 FeignLoggerFactory 和 FormattingConversionService 等。另外,Decoder、Encoder和 Contract 这3个类在没有Bean被注入的情况下,会自动注入默认配置的 Bean,即ResponseEntity Decoder、SpringEncoder 和 SpringMvcContract。

如果你不知道如何自己定义配置时,不放点进去看看人家默认配置是如何实现的。这里就不晒源码了。

FeignClient 注解参数

每个注解参数都做了注释,详情请见下方源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient { /**
* 指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现
*/
@AliasFor("name")
String value() default "";
@Deprecated
String serviceId() default "";
@AliasFor("value")
String name() default ""; /**
* Sets the <code>@Qualifier</code> value for the feign client.
* 这个bean在应用上下文中的名字为接口的全限定名,你也可以使用 @FeignClient 注解中的 qualifier 属性给bean指定一个别名
*/
String qualifier() default ""; /**
* url地址
*/
String url() default ""; /**
* 当发生404错误,如果该字段为true,会调用decoder进行解码,否则抛出FeignException
*/
boolean decode404() default false; /**
* 指定FeignClient 的配置类,优先级最高,默认的配置类为 FeignClientsConfiguration类
*/
Class<?>[] configuration() default {}; /**
* 配置熔断器的处理类
*/
Class<?> fallback() default void.class; /**
* 工厂类,用于生产fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复代码
*/
Class<?> fallbackFactory() default void.class; /**
* 定义统一的路径前缀
*/
String path() default ""; /**
* Whether to mark the feign proxy as a primary bean. Defaults to true.
*/
boolean primary() default true;
}

自定义Feign配置类

在 Spring Cloud 中,你可以通过 @FeignClient 注解声明额外的配置(比 FeignClientsConfiguration 级别高)去控制feign客户端,以一开始的feign接口为例:

/**
* @author axin
* @suammry xx 客户端
*/
@FeignClient(value = "xxClient",url = "${xx.host:www.axin.com}",configuration = MyConfiguration.class)
public interface DemoClient { @PostMapping(value = "/xxx/url", headers = "Content-Type=application/json"})
yourResponse requestHTTP(@RequestBody JSONObject param);
}

在上面这个示例中,feign客户端在MyConfiguration中的配置将会覆盖FeignClientsConfiguration中的配置。

要注意的是: MyConfiguration不需要使用@Configuration注解。如果加上了,它将全局生效

Retryer-重试机制的自定义

/**
* @author axin
* @summary fegin 客户端的自定义配置
*/
public class MyConfiguration { /**
* 自定义重试机制
* @return
*/
@Bean
public Retryer feignRetryer() {
//fegin提供的默认实现,最大请求次数为5,初始间隔时间为100ms,下次间隔时间1.5倍递增,重试间最大间隔时间为1s,
return new Retryer.Default();
}
}

ErrorDecoder-错误解码器的自定义

当feign调用返回HTTP报文时,会触发这个方法,方法内可以获得HTTP状态码,可以用来定制一些处理逻辑等等。

/**
* @author axin
* @summary fegin 客户端的自定义配置
*/
@Slf4j
public class MyConfiguration { /**
* 自定义重试机制
* @return
*/
@Bean
public Retryer feignRetryer() {
//最大请求次数为5,初始间隔时间为100ms,下次间隔时间1.5倍递增,重试间最大间隔时间为1s,
return new Retryer.Default();
} @Bean
public ErrorDecoder feignError() {
return (key, response) -> {
if (response.status() == 400) {
log.error("请求xxx服务400参数错误,返回:{}", response.body());
} if (response.status() == 409) {
log.error("请求xxx服务409异常,返回:{}", response.body());
} if (response.status() == 404) {
log.error("请求xxx服务404异常,返回:{}", response.body());
} // 其他异常交给Default去解码处理
// 这里使用单例即可,Default不用每次都去new
return new ErrorDecoder.Default().decode(key, response);
};
} }

采用了lambda的写法,response变量是Response类型,通过status()方法可以拿到返回的HTTP状态码,body()可以获得到响应报文。

Feign拦截器实践

拦截器在请求发出之前执行,在拦截器代码里可以修改请求参数,header等等,如果你有签名生成的需求,可以放在拦截器中来实现

/**
* @author axin
* @summary fegin 客户端的自定义配置
*/
@Slf4j
public class MyConfiguration { /**
* 自定义重试机制
* @return
*/
@Bean
public Retryer feignRetryer() {
//最大请求次数为5,初始间隔时间为100ms,下次间隔时间1.5倍递增,重试间最大间隔时间为1s,
return new Retryer.Default();
} @Bean
public ErrorDecoder feignError() {
return (key, response) -> {
if (response.status() == 400) {
log.error("请求xxx服务400参数错误,返回:{}", response.body());
} if (response.status() == 409) {
log.error("请求xxx服务409异常,返回:{}", response.body());
} if (response.status() == 404) {
log.error("请求xxx服务404异常,返回:{}", response.body());
} // 其他异常交给Default去解码处理
// 这里使用单例即可,Default不用每次都去new
return new ErrorDecoder.Default().decode(key, response);
};
} /**
* fegin 拦截器
* @return
*/
@Bean
public RequestInterceptor cameraSign() {
return template -> { // 如果是get请求
if (template.method().equals(Request.HttpMethod.GET.name())) {
//获取到get请求的参数
Map<String, Collection<String>> queries = template.queries();
} //如果是Post请求
if (template.method().equals(Request.HttpMethod.POST.name())) {
//获得请求body
String body = template.requestBody().asString();
JSONPObject request = JSON.parseObject(body, JSONPObject.class);
} //Do what you want... 例如生成接口签名 String sign = "根据请求参数生成的签名";
//放入url?之后
template.query("sign", sign); //放入请求body中
String newBody = "原有body" + sign;
template.body(Request.Body.encoded(newBody.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8));
};
}
}

可以看到代码中给了如何获取请求参数和修改请求参数的示例。

总结

小结一下,对于开头提出的场景:

  1. 我想在发起请求响应超时失败时自动重试 —— 自定义重试机制
  2. 我想单独对某些异常的HTTP状态码特殊处理 —— 自定义ErrorDecoder
  3. 服务端接口需要验证签名,所以我方在发起请求时要生成签名然后传过去 —— 定义 Fegin 拦截器

给出了自定义 feign 配置的方式实现的样例代码,希望对你有用,如果有更好的方式简化HTTP请求,欢迎留言分享~

参考链接

Spring Cloud Feign 自定义配置(重试、拦截与错误码处理) 实践的更多相关文章

  1. 笔记:Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  2. 笔记:Spring Cloud Feign Hystrix 配置

    在 Spring Cloud Feign 中,除了引入了用户客户端负载均衡的 Spring Cloud Ribbon 之外,还引入了服务保护与容错的工具 Hystrix,默认情况下,Spring Cl ...

  3. Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  4. 笔记:Spring Cloud Feign 其他配置

    请求压缩 Spring Cloud Feign 支持对请求与响应进行GZIP压缩,以减少通信过程中的性能损耗,我们只需要通过下面二个参数设置,就能开启请求与响应的压缩功能,yml配置格式如下: fei ...

  5. Spring Cloud Feign 声明式服务调用

    目录 一.Feign是什么? 二.Feign的快速搭建 三.Feign的几种姿态 参数绑定 继承特性 四.其他配置 Ribbon 配置 Hystrix 配置 一.Feign是什么? ​ 通过对前面Sp ...

  6. Spring Cloud Feign 在调用接口类上,配置熔断 fallback后,输出异常

    Spring Cloud Feign 在调用接口类上,配置熔断 fallback后,出现请求异常时,会进入熔断处理,但是不会抛出异常信息. 经过以下配置,可以抛出异常: 将原有ErrorEncoder ...

  7. 微服务架构之spring cloud feign

    在spring cloud ribbon中我们用RestTemplate实现了服务调用,可以看到我们还是需要配置服务名称,调用的方法 等等,其实spring cloud提供了更优雅的服务调用方式,就是 ...

  8. Spring cloud Feign 深度学习与应用

    简介 Spring Cloud Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单.Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解 ...

  9. spring coud Feign常用配置

    Ribbon配置 在Feign中配置Ribbon非常简单,直接在application.properties中配置即可,如: # 设置连接超时时间 ribbon.ConnectTimeout=500 ...

随机推荐

  1. 【JMicro】微服务开发及使用

    JMicro是一个用Java语言实现的开源微服务全家桶, 源码地址:https://github.com/mynewworldyyl/jmicro, Demo地址:http://124.70.152. ...

  2. PHP vprintf() 函数

    实例 输出格式化的字符串: <?php高佣联盟 www.cgewang.com$number = 9;$str = "Beijing";vprintf("There ...

  3. C++程序员容易走入性能优化误区!对此你怎么看呢?

    有些C++ 程序员,特别是只写C++ 没有写过 Python/PHP 等慢语言的程序员,容易对性能有心智负担,就像着了魔一样,每写3 行代码必有一行代码因为性能考虑而优化使得代码变形(复杂而晦涩). ...

  4. PHP+Redis实现高并发下商品超卖问题

    对于一些有一定用户量的电商网站,如果只是单纯的使用关系型数据库(如MySQL.Oracle)来做抢购,对数据库的压力是非常大的,而且如果不使用好数据库的锁机制,还会导致商品.优惠券超卖的问题.我所在的 ...

  5. 【CF600E】Lomset gelral 题解(树上启发式合并)

    题目链接 题目大意:给出一颗含有$n$个结点的树,每个节点有一个颜色.求树中每个子树最多的颜色的编号和. ------------------------- 树上启发式合并(dsu on tree). ...

  6. 十分钟搭建自己的私有NuGet服务器-BaGet

    目录 前言 开始 搭建BaGet 上传程序包 在vs中使用 其他 最后 前言 NuGet是用于微软.NET(包括 .NET Core)开发平台的软件包管理器.NuGet能够令你在项目中添加.移除和更新 ...

  7. 使用 Python 为女神挑选口红

    口红对于女生来说永远不嫌多,而男生也搞不明白珊瑚红.番茄色.斩男色等等颜色有什么区别,不都是红色么?当送给女神的口红是她不适合的,那结果就是口红进入垃圾箱还算是轻的,重则拉黑处理.男生们也不用着急,我 ...

  8. webgl实现发光线框(glow wireframe)效果

    在之前这篇文章, WebGL 单通道wireframe渲染 我们介绍了webgl如何实现单通道wireframe的效果. 本篇文章就是在此技术原理基础之上,来实现发光的wireframe效果. 要实现 ...

  9. Bystack跨链技术源码解读

    Bystack是由比原链团队提出的一主多侧链架构的BaaS平台.其将区块链应用分为三层架构:底层账本层,侧链扩展层,业务适配层.底层账本层为Layer1,即为目前比较成熟的采用POW共识的Bytom公 ...

  10. nvcc fatal : Path to libdevice library not specified

    安装完成后,配置环境变量,在home下的.bashrc中加入 export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH export ...