spring-projects / spring-projects/spring-framework
Provide `RequestPredicate` with no side effects
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 60.2k
- Forks
- 38.8k
- Avg merge
- 5d 2h
- Merged PRs (30d)
- 27
Description
I'm developing a Spring WebFlux application that serve Single Page Application front-end resources.
I have registered front-end resources in the ResourceHandlerRegistry for distribution, but some of them have had to change the Cache-Control header.
The ResourceHandlerRegistry cannot dynamically set the response headers according to the request URL or file extension.
I figured this goal could be accomplished with the WebFilter as well as the Servet API.
I used WebFilter in WebFlux to check the HTTP request and tried to change the HTTP header of the response, but the
I've noticed that WebFlux has different caveats than the Servlet API.
e.g, when I was getting a path from ServerHttpRequest, I had to call request.getPath().pathWithinApplication() or else the context path would be included.
Spring MVC provided an AntMatcher, so I looked for Spring WebFlux to provide a useful matcher as well, so I found the RequestPredicate, but this is a class for the RouterFunction and seems to have some side effects.
e.g, RequestPredicates#path(String) rewrites the path variable in the request.
I then discovered that Spring Security had a ServerWebExchangeMatchers with no side effects, and I implemented my own matcher based on its implementation.
But this is reinventing the wheel.
I was referring to the Spring Security implementation in this case, but I think it would be a time saver for someone like me who wants to do conditional processing with WebFilter, if a similar feature was provided as part of Spring WebFlux.
The following code is a sample of my WebFilter implementation.
my.application.matcher.ServerWebExchangeMatcher is a matcher based on Spring Security ServerWebExchangeMatchers.
package my.application;
import java.util.List;
import my.application.matcher.ServerWebExchangeMatcher;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
public class NoCacheWebFilter implements WebFilter {
public static final String CACHE_CONTROL_VALUE = "no-cache, no-store, max-age=0, must-revalidate";
public static final String PRAGMA_VALUE = "no-cache";
public static final String EXPIRES_VALUE = "0";
private final ServerWebExchangeMatcher serverWebExchangeMatcher;
public NoCacheWebFilter(
ServerWebExchangeMatcher serverWebExchangeMatcher) {
this.serverWebExchangeMatcher = serverWebExchangeMatcher;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
if (this.serverWebExchangeMatcher.matches(exchange)) {
exchange.getResponse().beforeCommit(() ->
Mono.fromRunnable(() -> writeNoCacheHeader(exchange)));
}
return chain.filter(exchange);
}
private void writeNoCacheHeader(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
if (response.getStatusCode() == HttpStatus.NOT_MODIFIED) {
return;
}
HttpHeaders responseHeaders = response.getHeaders();
responseHeaders.put(HttpHeaders.CACHE_CONTROL, List.of(CACHE_CONTROL_VALUE));
responseHeaders.put(HttpHeaders.PRAGMA, List.of(PRAGMA_VALUE));
responseHeaders.put(HttpHeaders.EXPIRES, List.of(EXPIRES_VALUE));
}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing the side effects of RequestPredicates#path(String) with the referenced ServerWebExchangeMatchers implementation. Review the sample NoCacheWebFilter and its ServerWebExchangeMatcher usage to understand the WebFilter use case. Done means WebFlux provides a side-effect-free request matcher suitable for conditional WebFilter processing.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100