Add advice on using exchange from an ExchangeFilterFunction
Closes gh-26819
This commit is contained in:
parent
5740eaf33e
commit
d25ae4b02c
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -39,6 +39,13 @@ public interface ExchangeFilterFunction {
|
||||||
* in the chain, to be invoked via
|
* in the chain, to be invoked via
|
||||||
* {@linkplain ExchangeFunction#exchange(ClientRequest) invoked} in order to
|
* {@linkplain ExchangeFunction#exchange(ClientRequest) invoked} in order to
|
||||||
* proceed with the exchange, or not invoked to shortcut the chain.
|
* proceed with the exchange, or not invoked to shortcut the chain.
|
||||||
|
*
|
||||||
|
* <p><strong>Note:</strong> When a filter handles the response after the
|
||||||
|
* call to {@link ExchangeFunction#exchange}, extra care must be taken to
|
||||||
|
* always consume its content or otherwise propagate it downstream for
|
||||||
|
* further handling, for example by the {@link WebClient}. Please, see the
|
||||||
|
* reference documentation for more details on this.
|
||||||
|
*
|
||||||
* @param request the current request
|
* @param request the current request
|
||||||
* @param next the next exchange function in the chain
|
* @param next the next exchange function in the chain
|
||||||
* @return the filtered response
|
* @return the filtered response
|
||||||
|
|
|
@ -43,6 +43,14 @@ public interface ExchangeFunction {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exchange the given request for a {@link ClientResponse} promise.
|
* Exchange the given request for a {@link ClientResponse} promise.
|
||||||
|
*
|
||||||
|
* <p><strong>Note:</strong> When a calling this method from an
|
||||||
|
* {@link ExchangeFilterFunction} that handles the response in some way,
|
||||||
|
* extra care must be taken to always consume its content or otherwise
|
||||||
|
* propagate it downstream for further handling, for example by the
|
||||||
|
* {@link WebClient}. Please, see the reference documentation for more
|
||||||
|
* details on this.
|
||||||
|
*
|
||||||
* @param request the request to exchange
|
* @param request the request to exchange
|
||||||
* @return the delayed response
|
* @return the delayed response
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -889,9 +889,8 @@ a filter for basic authentication through a static factory method:
|
||||||
.build()
|
.build()
|
||||||
----
|
----
|
||||||
|
|
||||||
You can create a new `WebClient` instance by using another as a starting point. This allows
|
Filters can be added or removed by mutating an existing `WebClient` instance, resulting
|
||||||
insert or removing filters without affecting the original `WebClient`. Below is an example
|
in a new `WebClient` instance that does not affect the original one. For example:
|
||||||
that inserts a basic authentication filter at index 0:
|
|
||||||
|
|
||||||
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
.Java
|
.Java
|
||||||
|
@ -912,6 +911,53 @@ that inserts a basic authentication filter at index 0:
|
||||||
.build()
|
.build()
|
||||||
----
|
----
|
||||||
|
|
||||||
|
`WebClient` is a thin facade around the chain of filters followed by an
|
||||||
|
`ExchangeFunction`. It provides a workflow to make requests, to encode to and from higher
|
||||||
|
level objects, and it helps to ensure that response content is always consumed.
|
||||||
|
When filters handle the response in some way, extra care must be taken to always consume
|
||||||
|
its content or to otherwise propagate it downstream to the `WebClient` which will ensure
|
||||||
|
the same. Below is a filter that handles the `UNAUTHORIZED` status code but ensures that
|
||||||
|
any response content, whether expected or not, is released:
|
||||||
|
|
||||||
|
[source,java,indent=0,subs="verbatim,quotes",role="primary"]
|
||||||
|
.Java
|
||||||
|
----
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
[source,kotlin,indent=0,subs="verbatim,quotes",role="secondary"]
|
||||||
|
.Kotlin
|
||||||
|
----
|
||||||
|
fun renewTokenFilter(): ExchangeFilterFunction? {
|
||||||
|
return ExchangeFilterFunction { request: ClientRequest?, next: ExchangeFunction ->
|
||||||
|
next.exchange(request!!).flatMap { response: ClientResponse ->
|
||||||
|
if (response.statusCode().value() == HttpStatus.UNAUTHORIZED.value()) {
|
||||||
|
return@flatMap response.releaseBody()
|
||||||
|
.then(renewToken())
|
||||||
|
.flatMap { token: String? ->
|
||||||
|
val newRequest = ClientRequest.from(request).build()
|
||||||
|
next.exchange(newRequest)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return@flatMap Mono.just(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[webflux-client-attributes]]
|
[[webflux-client-attributes]]
|
||||||
== Attributes
|
== Attributes
|
||||||
|
|
Loading…
Reference in New Issue