如何使用Spring Webflux实现/迁移OncePerRequestFilter

时间:2019-12-11 15:24:15

标签: spring spring-boot spring-webflux

使用Spring web,简单的OncePerRequestFilter(请参见下文)可以维护请求范围内的请求ID。 将生成的请求ID存储在request属性中,将其添加到日志记录的MDC中,然后返回响应标头。

我知道反应式webflux堆栈是完全不同的,那么应该如何解决呢?

我找到了https://github.com/spring-projects/spring-framework/issues/20239,但不清楚现在是否支持什么。

@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();
    }
}

1 个答案:

答案 0 :(得分:1)

在WebFlux中不需要OncePerRequestFilter实现,因为过滤器仅执行一次,因为WebFlux不支持请求转发(例如Servlet中的请求转发)。

现在您可以实现一个WebFilter,它添加requestId作为请求属性,非常类似于您所显示的版本。

有几件事要注意:

  • 您应避免在反应性管道UUID.randomUUID() is blocking
  • 中调用阻塞方法
  • 在响应式环境中将数据添加到MDC并不容易,因为此功能最初依赖于ThreadLocal。立即查看this blog post,并关注this issue for more guidance
  • 牢记此用例,听起来Spring Cloud Sleuth可能会实现您想要的目标,甚至更多(支持范围等)。