ITPub博客

首页 > 数据库 > 数据库开发技术 > OpenFeign的RequestInterceptor组件你用过哪些场景?

OpenFeign的RequestInterceptor组件你用过哪些场景?

原创 数据库开发技术 作者:服务端技术栈 时间:2023-06-28 08:10:00 0 删除 编辑

前言

前几篇文章已经分析过了OpenFeign的Client组件和重试组件。

Feign框架最核心可扩展组件通信Client详解

OpenFeign是怎样集成Ribbon负载均衡能力的?

OpenFeign集成Ribbon负载均衡-过滤和选择服务核心实现

OpenFeign重试组件Retryer原理

今天开始分析OpenFeign的第3个组件RequestInterceptor。

RequestInterceptor是在发起远程请求前对请求对象进行拦截的,这个组件其实使用场景挺常见的。比如传递公用的参数,对feign请求url进行限流计数,编码等场景,下面我们来详细看看他的原理。


RequestInterceptor组成

我们需要先看下RequestInterceptor的组成。

package feign;
public interface RequestInterceptor { void apply(RequestTemplate var1);}

RequestInterceptor是一个接口,接口里只有一个apply方法,apply方法接受请求模板RequestTemplate对象,它是在哪里调用的呢?

我们可以看到OpenFeign执行请求的方法

feign.SynchronousMethodHandler#executeAndDecode中 

Object executeAndDecode(RequestTemplate template) throws Throwable {        //这里会对请求做一次拦截处理        Request request = this.targetRequest(template);                long start = System.nanoTime();        Response response;        try {            response = this.client.execute(request, this.options);        //...
return var9; }

//对请求拦截器进行应用 Request targetRequest(RequestTemplate template) { Iterator var2 = this.requestInterceptors.iterator();
while(var2.hasNext()) { //循环每个拦截器进行应用到请求对象 RequestInterceptor interceptor = (RequestInterceptor)var2.next(); interceptor.apply(template); }
return this.target.apply(template); }

RequestInterceptor能够帮我们做什么呢?我们看下RequestTemplate类的组成 

public final class RequestTemplate implements Serializable {    private static final Pattern QUERY_STRING_PATTERN = Pattern.compile("(?<!\\{)\\?");    private final Map<String, QueryTemplate> queries = new LinkedHashMap();    private final Map<String, HeaderTemplate> headers;    private String target;    private String fragment;    private boolean resolved;    private UriTemplate uriTemplate;    private HttpMethod method;    private transient Charset charset;    private Body body;    private boolean decodeSlash;    private CollectionFormat collectionFormat;


里面有几个非常熟悉的字段:

  •  queries是存储请求的参数

  •  headers存储请求头

  •  uriTemplate存储请求url


    RequestInterceptor使用案例


就是上面这三个字段,工作中可以用来解决一些问题。

一、压缩请求传输的数据

OpenFeign内置已经做了一些扩展,我们对一些请求响应时间性能要求比较高的场景,通常需要对请求传输的数据进行压缩。OpenFeign内置了gzip压缩算法的实现

  • FeignContentGzipEncodingInterceptor 压缩请求体

  • FeignAcceptGzipEncodingInterceptor 压缩响应体

这两个配置项项目中有没有用过呢?通过这两个项目就可以开启压缩功能了

feign.compression.request.enabled、 feign.compression.response.enabled

他们都是通过FeignAcceptGzipEncodingAutoConfiguration自动装配类实现的

  • 开启响应压缩

@Configuration@EnableConfigurationProperties({FeignClientEncodingProperties.class})@ConditionalOnClass({Feign.class})@ConditionalOnBean({Client.class})@ConditionalOnProperty(    value = {"feign.compression.response.enabled"},    matchIfMissing = false)@ConditionalOnMissingBean(    type = {"okhttp3.OkHttpClient"})@AutoConfigureAfter({FeignAutoConfiguration.class})public class FeignAcceptGzipEncodingAutoConfiguration {    public FeignAcceptGzipEncodingAutoConfiguration() {    }
//响应压缩拦截器 @Bean public FeignAcceptGzipEncodingInterceptor feignAcceptGzipEncodingInterceptor(FeignClientEncodingProperties properties) { return new FeignAcceptGzipEncodingInterceptor(properties); }}


  • 开启请求压缩

@Configuration@EnableConfigurationProperties(FeignClientEncodingProperties.class)@ConditionalOnClass(Feign.class)@ConditionalOnBean(Client.class)// The OK HTTP client uses "transparent" compression.// If the content-encoding header is present it disable transparent compression@ConditionalOnMissingBean(type = "okhttp3.OkHttpClient")@ConditionalOnProperty(value = "feign.compression.request.enabled", matchIfMissing = false)@AutoConfigureAfter(FeignAutoConfiguration.class)public class FeignContentGzipEncodingAutoConfiguration {
@Bean public FeignContentGzipEncodingInterceptor feignContentGzipEncodingInterceptor( FeignClientEncodingProperties properties) { return new FeignContentGzipEncodingInterceptor(properties); }
}

需要注意的是如果使用okhttp通信客户端,okhttp是支持transparent compression压缩的,因此上面的配置都是在非okhttp客户端的情况下生效。


二、透传TraceId,请求计数,监控打点等

如果我们需要对一些请求传一些固定的参数,比如token,或者接入统一的监控平台,一般会使用请求拦截器实现。

比如下方案例,通过RequestInterceptor传递traceId,请求计数

public class TraceIdInterceptor implements RequestInterceptor {        AtomicLong uriAtomicLong = new AtomicLong();
@Override public void apply(RequestTemplate requestTemplate) { //传递traceid给下游系统 requestTemplate.header("traceId", UUID.fastUUID().toString(true));
String url = requestTemplate.url(); long accessCount = uriAtomicLong.incrementAndGet(); //上报访问次数... }


RequestInterceptor生效

以上面TraceIdInterceptor为例,如何使RequestInterceptor生效呢?

一、全局生效

通过配置类的方式,增加@Configuration注解,让Spring容器扫描到,这样就会对所有FeignClient生效。

@Configurationpublic class FeignClientConfiguration {
@Bean public TraceIdInterceptor interceptor() { return new TraceIdInterceptor(); }}


二、针对指定FeignClient生效

如果想只对某些FeignClient生效,需要创建一个配置类,同时在FeignClient中指定configuration配置类属性。

public class FeignClientConfiguration {
@Bean public TraceIdInterceptor interceptor() { return new TraceIdInterceptor(); }}

@FeignClient(value = "fox-server", configuration = TestFeignClientConfiguration.class)public interface FeignService { @PostMapping("/get") String getName(@RequestBody @Validated DemoRequest request);}

注意这种情况FeignClientConfiguration是没有增加@Configuration,不会被Spring容器扫描到的。

总结

RequestInterceptor是OpenFeign提供一个对Feign请求拦截的组件,能够在发起请求前对header,body进行修改,一般用来实现一些非业务功能的需求,比如公用参数,监控,打点,压缩等,支持对全局FeignClient生效,也支持对部分FeignClient生效。

关于RequestInterceptor的分析结束了,你有没有更多的使用场景案例呢,欢迎评论区分享给大家。


原文作者:服务端技术栈;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-03-08

  • 博文量
    97
  • 访问量
    41428