OpenFeign请求拦截器组件RequestInterceptor原理与使用场景

简介: 该文章讲述了OpenFeign中的请求拦截器组件RequestInterceptor的原理及其常见使用场景。

前言

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

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

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

RequestInterceptor组成

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

package feign;

public interface RequestInterceptor {
   
   

void apply(RequestTemplate var1);

}

RequestInterceptor 是一个接口,apply方法接受请求模版RequestTemplate对象,

我们可以看到 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);
}

RequestTemplate组成

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;
//请求url
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.enabledfeign.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);
    }

}

image.png

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

二、透传tocken,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生效。

@Configuration
public 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的分析结束了,你有没有更好的使用场景案例呢,欢迎评论区分享给大家。

image.png

相关文章
|
2月前
|
Java 程序员 API
《Spring Boot应用进阶:打造优雅的错误处理机制与全局异常拦截器》
《Spring Boot应用进阶:打造优雅的错误处理机制与全局异常拦截器》
146 0
|
5月前
|
负载均衡 Java API
通用快照方案问题之Feign添加请求拦截器如何解决
通用快照方案问题之Feign添加请求拦截器如何解决
44 1
|
6月前
|
存储 缓存 负载均衡
OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用
OpenFeign高级用法:缓存、QueryMap、MatrixVariable、CollectionFormat优雅地远程调用
|
7月前
|
JSON Java 关系型数据库
【Feign】 基于 Feign 远程调用、 自定义配置、性能优化、实现 Feign 最佳实践
【Feign】 基于 Feign 远程调用、 自定义配置、性能优化、实现 Feign 最佳实践
298 0
|
数据采集 监控 Java
Spring Boot拦截器:精细化控制请求与响应
本篇详细介绍了在Spring Boot中使用拦截器的方法。拦截器是一种强大的机制,可用于在请求处理前后进行操作,如鉴权、日志记录等。文章涵盖了创建拦截器类、注册拦截器以及实际应用案例。通过具体的代码示例,读者可以了解如何在项目中配置和使用拦截器,以实现各种功能需求。拦截器为Spring Boot应用增加了更多的灵活性和可扩展性,能够提升应用的安全性和可维护性。
2696 0
Spring Boot拦截器:精细化控制请求与响应
|
设计模式 JSON 前端开发
SpringMVC入门-注解配置和请求传参和响应数据 2
SpringMVC入门-注解配置和请求传参和响应数据
79 0
|
JSON JavaScript 前端开发
SpringMVC入门-注解配置和请求传参和响应数据 1
SpringMVC入门-注解配置和请求传参和响应数据
107 0
|
负载均衡 Java 数据处理
案例03-fegin调用报404问题
fegin调用报404问题
168 0
|
SQL 监控 前端开发
Springboot过滤器和拦截器详解及使用场景
过滤器和拦截器触发时机不一样,过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
|
Java Spring
Spring Boot 监听器、拦截器以及过滤器的作用、差异?
Spring Boot 监听器、拦截器以及过滤器的作用、差异?
231 0