跳到主要内容

过滤器

ChatGPT-4o 中英对照 Filters

您可以通过 WebClient.Builder 注册一个客户端过滤器(ExchangeFilterFunction)来拦截和修改请求,如下例所示:

WebClient client = WebClient.builder()
.filter((request, next) -> {

ClientRequest filtered = ClientRequest.from(request)
.header("foo", "bar")
.build();

return next.exchange(filtered);
})
.build();
java

这可以用于横切关注点,例如身份验证。以下示例通过静态工厂方法使用过滤器进行基本身份验证:

import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;

WebClient client = WebClient.builder()
.filter(basicAuthentication("user", "password"))
.build();
java

可以通过修改现有的 WebClient 实例来添加或移除过滤器,从而生成一个新的 WebClient 实例,而不会影响原始实例。例如:

import static org.springframework.web.reactive.function.client.ExchangeFilterFunctions.basicAuthentication;

WebClient client = webClient.mutate()
.filters(filterList -> {
filterList.add(0, basicAuthentication("user", "password"));
})
.build();
java

WebClient 是一个围绕过滤器链以及 ExchangeFunction 的薄封装。它提供了一种工作流程来发起请求,进行高层对象的编码和解码,并帮助确保响应内容始终被消费。当过滤器以某种方式处理响应时,必须格外小心,以始终消费其内容或将其传播到下游的 WebClient,后者将确保同样的事情。下面是一个处理 UNAUTHORIZED 状态码的过滤器,但确保无论响应内容是否预期,都会被释放:

public ExchangeFilterFunction renewTokenFilter() {
return (request, next) -> next.exchange(request).flatMap(response -> {
if (response.statusCode().value() == HttpStatus.UNAUTHORIZED.value()) {
return response.releaseBody()
.then(renewToken())
.flatMap(token -> {
ClientRequest newRequest = ClientRequest.from(request).build();
return next.exchange(newRequest);
});
} else {
return Mono.just(response);
}
});
}
java

下面的示例演示了如何使用 ExchangeFilterFunction 接口创建一个自定义过滤器类,该类通过缓冲来帮助计算 PUTPOST multipart/form-data 请求的 Content-Length 头。

public class MultipartExchangeFilterFunction implements ExchangeFilterFunction {

@Override
public Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next) {
if (MediaType.MULTIPART_FORM_DATA.includes(request.headers().getContentType())
&& (request.method() == HttpMethod.PUT || request.method() == HttpMethod.POST)) {
return next.exchange(ClientRequest.from(request).body((outputMessage, context) ->
request.body().insert(new BufferingDecorator(outputMessage), context)).build()
);
} else {
return next.exchange(request);
}
}

private static final class BufferingDecorator extends ClientHttpRequestDecorator {

private BufferingDecorator(ClientHttpRequest delegate) {
super(delegate);
}

@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
return DataBufferUtils.join(body).flatMap(buffer -> {
getHeaders().setContentLength(buffer.readableByteCount());
return super.writeWith(Mono.just(buffer));
});
}
}
}
java