Marcel Overdijk
Marcel Overdijk

Reputation: 11467

How to implement/migrate OncePerRequestFilter using Spring webflux

Using Spring web a simple OncePerRequestFilter (see below) can maintain a request id for the span of the request. Storing the generated request id in a request attribute, adding it to the logging MDC, and returning in a response header.

I understand the reactive webflux stack is completely different, so how should one tackle this?

I found https://github.com/spring-projects/spring-framework/issues/20239 but it is not clear what is now supported or not.

@Component
public class RequestIdFilter extends OncePerRequestFilter implements Ordered {

    private static final String MDC_KEY = "requestId";
    private static final String REQUEST_ATTRIBUTE_NAME = "requestId";
    private static final String RESPONSE_HEADER_NAME = "X-Request-Id";


    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        var requestId = UUID.randomUUID().toString();
        MDC.put(MDC_KEY, requestId);
        request.setAttribute(REQUEST_ATTRIBUTE_NAME, requestId);
        response.setHeader(RESPONSE_HEADER_NAME, requestId);
        try {
            filterChain.doFilter(request, response);
        } finally {
            MDC.remove(MDC_KEY);
        }
    }

    @Override
    public int getOrder() {
        return requestIdProperties.getServerFilterOrder();
    }
}

Upvotes: 7

Views: 8000

Answers (1)

Brian Clozel
Brian Clozel

Reputation: 59141

You don't need a OncePerRequestFilter implementation in WebFlux, as Filters are executed only once because request forwarding (like in Servlet) is not supported in WebFlux.

Now you can implement a WebFilter that adds a requestId as a request attribute, pretty much like the version you're showing.

There are several things to pay attention to:

  • you should avoid calling blocking methods within your reactive pipeline, UUID.randomUUID() is blocking
  • Adding data to the MDC is not straightforward in a reactive environment, since this feature originally relies on ThreadLocal. See this blog post for now and keep an eye on this issue for more guidance
  • with this use case in mind, it sounds like Spring Cloud Sleuth might achieve what you want, and more (supporting spans, etc).

Upvotes: 5

Related Questions