0

I am looking for servlet Filter equivalent in Spring WebFlux. The WebFilter seems to only fires before the controller but not after. e.g I can add a WebFilter to do something when a request comes in, but I couldn't find an equivalent "filter" to do something when a response is sending back.

Can you have a "filter" that fires in both ways?

user1589188
  • 5,316
  • 17
  • 67
  • 130
  • Does this answer your question? [How to intercept a request when using SpringBoot WebClient](https://stackoverflow.com/questions/51726943/how-to-intercept-a-request-when-using-springboot-webclient) – dekkard Jun 01 '22 at 07:48
  • @dekkard Sorry no, if I understand it correctly, that one you posted is for a `WebClient`, while I am after something for my server – user1589188 Jun 01 '22 at 08:05

3 Answers3

0

You can still use WebFilter to modify your server's outbound responses as well. Here's an example of adding a header to the response:

@Component
public class ExampleWebFilter implements WebFilter {
 
    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, 
      WebFilterChain webFilterChain) {
        
        serverWebExchange.getResponse()
          .getHeaders().add("web-filter", "web-filter-test");
        return webFilterChain.filter(serverWebExchange);
    }
}

Reference: https://www.baeldung.com/spring-webflux-filters

dekkard
  • 6,121
  • 1
  • 16
  • 26
  • Yes I know it can modifies both the request and the response, but the issue is `WebFilter#filter()` happens only before the actual controller, but not after. – user1589188 Jun 01 '22 at 08:24
  • That is no so for webflux. In any case I don't see why such internal implementation details even matter when this clearly does what you requested. – dekkard Jun 01 '22 at 09:11
  • If it doesn't fire after the controller, how do you act according to the response body sets by the controller? – user1589188 Jun 01 '22 at 09:15
  • 3
    In Webflux there's a single stream between a client and a server with data flowing both ways. As soon as we read the request or response body for processing, the input stream is consumed, so the controller or client doesn’t receive the body. So intercepting a request or response body in Webflux is not a trivial task. Have a look at https://stackoverflow.com/a/45280764/4571544 and https://stackoverflow.com/questions/61706948/how-to-log-request-body-in-spring-webflux-java for more info. – dekkard Jun 01 '22 at 09:55
0

Just add code after the webFilterChain.filter call.

@Component
public class MyFilter implements WebFilter {

@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
  Mono<Void> result = chain.filter(exchange);
  return result.then(<do-whatever>);
}
M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • Haha yeah nah, this just runs code after the other filters, not after controller during the outbound. – user1589188 Jun 01 '22 at 10:24
  • 3
    No it doesn't. The controller will be called after all filters processed and then it goes back up. At least it should. – M. Deinum Jun 01 '22 at 11:05
  • 1
    By definition `WebFilter` is executed before controller. You could look at special beans like `HandlerResultHandler` or consider [function WebFlux endpoints](https://spring.getdocs.org/en-US/spring-framework-docs/docs/spring-web-reactive/webflux/webflux-fn.html) that you could use to wrap handler and implement own logic. – Alex Jun 01 '22 at 14:37
  • > *Haha yeah nah, this just runs code after the other filters, not after controller during the outbound* According to your tone, may we assume that you have indeed tested and verified it? – BalusC Jun 02 '22 at 13:20
  • @BalusC yes confirmed – user1589188 Jul 13 '22 at 03:20
0

I think the trick you are looking for is when you call the filter chain in the filter method you want the following

@Override
public Mono<Void> filter(@NonNull final ServerWebExchange exchange, @NonNull final WebFilterChain chain) {
        final ServerHttpRequest request = exchange.getRequest();
        final String requestUrl = request.getURI().toString();
        
        // preRequest: - YOUR LOGIC

        return chain.filter(exchange).doFinally(signalType -> {
            /* This doFinally is included so the tests will pass */
            log.info("postHandle: Just like an interceptor");
        });
}
Rhineb
  • 305
  • 3
  • 12