New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ordering of WebClient.filter(s) [SPR-15657] #20216
Comments
Rossen Stoyanchev commented I can certainly relate to the expectation, seeing what looks like a list of filters. Fundamentally however this is a decoration-based mechanism. If you look inisde, Remember also that Another benefit of decoration is you can have the same WebClient instance used with a different set of filters. If I'm given a WebClient with filter1 and filter2, I can then decorate it with filterA and filterB and that won't affect any users of the WebClient passed to me (decorated with only filter1 and filter2). Considering that the word "filter" carries a strong association to a chain of Servlet Filter's perhaps we can consider changing the name |
Joe Grandja commented I think naming the method to Here's a more concrete example: this.webClient
.filter(applyAuthorizationHeader())
.filter(exchangeAndHandleAccessTokenErrorWithRefresh()) As a user, I might read this as follows:
But I will know quickly that this won't work because the I understand the |
Rossen Stoyanchev commented
Isn't this just: WebClient webClientA = WebClient.create("http://localhost:8080");
// pass this where you want instance without filters...
WebClient webClientB = webClientA.filter(filter1).filter(filter2);
// pass this where you want instance with filters... |
Joe Grandja commented Let's assume What |
Rossen Stoyanchev commented I get that you want to be able to unwrap the target WebClient without any filters but I don't see how this has anything to do with filter ordering. |
Arjen Poutsma commented
You're missing an quite important piece in that sample: the assignment of the return value from WebClient filteredClient = this.webClient
.filter(applyAuthorizationHeader())
.filter(exchangeAndHandleAccessTokenErrorWithRefresh()) or, to make it even clearer: WebClient filteredClient = this.webClient.filter(applyAuthorizationHeader());
filteredClient = filtedClient.filter(exchangeAndHandleAccessTokenErrorWithRefresh()); here, you are creating a filtered client by applying the The reason we took this approach, as Rossen already eluded to, is thread-safety: if That said, I still think we can improve the overall filtering experience by making it part of WebClient webClient = webClient.builder()
.addFilter(filter1)
.addFilter(filter2)
.build(); where Whether we want to keep As for getting access to the unfiltered |
Arjen Poutsma commented
|
Arjen Poutsma commented One more comment regarding the order of ExchangeFilterFunction filter = applyAuthorizationHeader().andThen(exchangeAndHandleAccessTokenErrorWithRefresh());
WebClient filteredClient = this.webClient.filter(filter); Here the |
Joe Grandja commented Rossen, in reference to your comment:
This allows me to control the order of filters, by starting fresh and re-adding the filters I want in a specific order. If I reuse a |
Joe Grandja commented Arjen, in reference to your comment:
Totally aware of the required variable assignment of I understand the reason for immutability and that totally makes sense. However, when |
Joe Grandja commented Arjen, I forgot about the option of |
Rossen Stoyanchev commented Arjen Poutsma I'm in favor of having I still think the |
Rob Winch commented I'm not actually that fond of |
Arjen Poutsma commented Here's what I suggest I do to resolve this issue: first, we add
I am starting to think that the issues we are seeing with So I suggest to drop |
Arjen Poutsma commented Rossen Stoyanchev suggested during today's meeting that removing |
Joe Grandja commented I do like the option of adding the filters via the Builder with the expectation that they are called in list order. Also, the ability to return the builder with the current configuration of the I'm going to put out another option to consider. Let's say we keep the public WebClient withFilter(ExchangeFilterFunction filterFunction) {
ExchangeFunction filteredExchangeFunction = this.exchangeFunction.andThen(filterFunction); This would allow the ordering to be consistent between However, this means we would need to add the default method Either way, another option to consider. |
Arjen Poutsma commented
The Adding a method |
Joe Grandja commented Arjen, thanks for the explanation. That totally makes sense. I did not put much thought into my suggestion for adding Given the way function chaining works via |
Arjen Poutsma commented Fixed in 4a0597d |
Arjen Poutsma commented I wasn't sure if we needed |
Rob Winch commented Arjen Poutsma Can we add the |
Arjen Poutsma commented |
Artem Bilan commented There is an NPE in the newly introduced |
Arjen Poutsma commented NPE fixed in 4f39edc |
spring-projects-issues commentedJun 13, 2017
•
edited
Joe Grandja opened SPR-15657 and commented
Given this filter configuration for
WebClient
:The expectation is that the filters would be applied in the following order:
filter1, filter2, filter3, filter4
. However, that is not the case, as they are applied in reverse order.It seems a bit confusing compared to the way a Reactive stream is defined and executed in a top-down approach (the way the code reads).
Does it make sense to have the filters applied in the order they are defined - top-down approach?
Affects: 5.0 RC1
Issue Links:
0 votes, 5 watchers
The text was updated successfully, but these errors were encountered: