首页 文章

Spring响应式应用程序上的请求/响应正文的副本?

提问于
浏览
3

我正在研究访问HTTP请求和响应主体的最佳方法,以便在Spring反应式应用程序中进行跟踪 .

对于以前的版本,我们利用Servlet过滤器和Servlet请求包装器来使用传入请求的输入流并保存它的副本以进行跟踪的异步处理(我们将它们发送到Elasticsearch) .

但是对于一个Spring响应式应用程序(使用webflux),我想知道在解码之前访问请求的最合适方式是什么 . 有什么想法吗?

1 回答

  • 5

    事实证明,这可以使用提供的装饰器来实现: ServerWebExchangeDecoratorServerHttpRequestDecoratorServerHttpResponseDecorator .

    这是一个示例请求装饰器,它将 DataBuffer 内容累积为请求的默认订阅者读取的内容:

    @Slf4j
    public class CachingServerHttpRequestDecorator extends ServerHttpRequestDecorator {
    
        @Getter
        private final OffsetDateTime timestamp = OffsetDateTime.now();
        private final StringBuilder cachedBody = new StringBuilder();
    
        CachingServerHttpRequestDecorator(ServerHttpRequest delegate) {
            super(delegate);
        }
    
        @Override
        public Flux<DataBuffer> getBody() {
            return super.getBody().doOnNext(this::cache);
        }
    
        @SneakyThrows
        private void cache(DataBuffer buffer) {
            cachedBody.append(UTF_8.decode(buffer.asByteBuffer())
             .toString());
        }
    
        public String getCachedBody() {
            return cachedBody.toString();
        }
    

    只需确保当你装饰 WebFilter 传递的 ServerWebExchange 时,你也会覆盖 getRequest() 以返回请求装饰器:

    public final class PartnerServerWebExchangeDecorator extends ServerWebExchangeDecorator {
    
        private final ServerHttpRequestDecorator requestDecorator;
        private final ServerHttpResponseDecorator responseDecorator;
    
        public PartnerServerWebExchangeDecorator(ServerWebExchange delegate) {
            super(delegate);
            this.requestDecorator = new PartnerServerHttpRequestDecorator(delegate.getRequest());
            this.responseDecorator = new PartnerServerHttpResponseDecorator(delegate.getResponse());
        }
    
        @Override
        public ServerHttpRequest getRequest() {
            return requestDecorator;
        }
    
        @Override
        public ServerHttpResponse getResponse() {
            return responseDecorator;
        }
    
    }
    

    在过滤器上:

    @Component
    public class TracingFilter implements WebFilter {
    
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
            return chain.filter(new PartnerServerWebExchangeDecorator(exchange));
        }
    }
    

    可以这样使用(注意静态导入的功能):

    @Bean
    public HttpHandler myRoute(MyHandler handler) {
        final RouterFunction<ServerResponse> routerFunction =
            route(POST("/myResource"), handler::persistNotification);
        return webHandler(toWebHandler(routerFunction))
            .filter(new TracingFilter())
            .build();
    }
    

相关问题