This is the multi-page printable view of this section.
Click here to print.
Return to the regular view of this page.
Filter
Filter
分为RequestFilter
和ResponseFilter
两种,前者主要用于处理HttpRequest
,在所有Interceptor
对HttpRequest
处理之后执行, 后者主要用于处理HttpResponse
,在响应headers到达之后立即执行,此时所有拦截器对HttpResponse
的处理均未开始执行。
与Interceptor
的区别
- 执行顺序不同:
RequestFilter
在所有拦截器对HttpRequest
的处理之后才会执行,ResponseFilter
在响应头接收到之后(响应body处理前)立即执行,此时所有拦截器对HttpResponse
的处理均未执行。
- 关联性不同:
RequestFilter
和ResponseFilter
中均无法同时获取到请求和响应,因此也不能将两者关联起来,但是同一个请求将在RequestFilter
和ResponseFilter
中共享一个FilterContext
实例,
因此可以通过该对象传递上下文参数。而Interceptor
中可以获取HttpRequest
经过处理后的HttpResponse
,因此可以通过此种方式将请求和响应关联起来。
- 通过
RequestFilter
或ResponseFilter
无法替换原始的HttpRequest
或HttpResponse
,而通过Interceptor
可以实现。
鉴于Filter
和Interceptor
的区别,下述场景更适合使用Filter
:
- 只需要单独处理
HttpRequest
或HttpResponse
,如:对每个HttpRequest
或HttpResponse
添加固定的请求header。
HttpRequest
处理过程中可能需要多次执行的逻辑,比如在发生重试、重定向时会发出多个网络请求,而这些请求均需要执行的逻辑。
Note
- 多个
Filter
之间通过getOrder()
方法返回值区分执行顺序,值越小,优先级越高
- 同一个
HttpRequest
可以通过共享一个FitlerContext
实例在多个RequestFilter
和ResponseFilter
实例间传递上下文参数
1 - 使用方式
HttpClient
支持通过builder配置和SPI加载两种方式配置Filter
。
Builder配置
final HttpClient client = HttpClient.create().addRequestFilter((request, ctx) -> { // 仅处理Request
System.out.println("Request Filter");
return CompletableFuture.completedFuture(null);
}).addResponseFilter((request, response, ctx) -> { // 仅处理Response
System.out.println("Response Filter");
return CompletableFuture.completedFuture(null);
}).addFilter(new DuplexFilter() { // 同时处理Request和Response
@Override
public CompletableFuture<Void> doFilter(HttpRequest request, FilterContext ctx) {
System.out.println("Request Filter(Duplex)");
return CompletableFuture.completedFuture(null);
}
@Override
public CompletableFuture<Void> doFilter(HttpRequest request, HttpResponse response, FilterContext ctx) {
System.out.println("Response Filter(Duplex)");
return CompletableFuture.completedFuture(null);
}
}).build();
SPI
HttpClient
支持通过SPI的方式加载Filter
,使用时,只需要按照Spi的加载规则将自定义的Filter
放入指定的目录下即可。