如何在 Spring WebFlux 中记录请求和响应主体 [英] How to log request and response bodies in Spring WebFlux

查看:63
本文介绍了如何在 Spring WebFlux 中记录请求和响应主体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望使用 Kotlin 在 Spring WebFlux 上的 REST API 中集中记录请求和响应.到目前为止,我已经尝试过这种方法

I want to have centralised logging for requests and responses in my REST API on Spring WebFlux with Kotlin. So far I've tried this approaches

@Bean
fun apiRouter() = router {
    (accept(MediaType.APPLICATION_JSON) and "/api").nest {
        "/user".nest {
            GET("/", userHandler::listUsers)
            POST("/{userId}", userHandler::updateUser)
        }
    }
}.filter { request, next ->
    logger.info { "Processing request $request with body ${request.bodyToMono<String>()}" }
    next.handle(request).doOnSuccess { logger.info { "Handling with response $it" } }
}

这里请求方法和路径记录成功,但是正文是Mono,那么我应该如何记录呢?是否应该反过来,我必须订阅请求正文 Mono 并将其记录在回调中?另一个问题是这里的 ServerResponse 接口无法访问响应正文.我怎么能在这里得到它?

Here request method and path log successfully but the body is Mono, so how should I log it? Should it be the other way around and I have to subscribe on request body Mono and log it in the callback? Another problem is that ServerResponse interface here doesn't have access to the response body. How can I get it here?

我尝试过的另一种方法是使用 WebFilter

Another approach I've tried is using WebFilter

@Bean
fun loggingFilter(): WebFilter =
        WebFilter { exchange, chain ->
            val request = exchange.request
            logger.info { "Processing request method=${request.method} path=${request.path.pathWithinApplication()} params=[${request.queryParams}] body=[${request.body}]"  }

            val result = chain.filter(exchange)

            logger.info { "Handling with response ${exchange.response}" }

            return@WebFilter result
        }

同样的问题:请求主体是 Flux 而没有响应主体.

Same problem here: request body is Flux and no response body.

有没有办法从某些过滤器访问完整的请求和响应以进行日志记录?我有什么不明白的?

Is there a way to access full request and response for logging from some filters? What don't I understand?

推荐答案

这或多或少类似于 Spring MVC 中的情况.

This is more or less similar to the situation in Spring MVC.

在 Spring MVC 中,您可以使用 AbstractRequestLoggingFilter 过滤器和 ContentCachingRequestWrapper 和/或 ContentCachingResponseWrapper.这里有许多权衡:

In Spring MVC, you can use a AbstractRequestLoggingFilter filter and ContentCachingRequestWrapper and/or ContentCachingResponseWrapper. Many tradeoffs here:

  • 如果您想访问 servlet 请求属性,您需要实际读取和解析请求正文
  • 记录请求正文意味着缓冲请求正文,这会占用大量内存
  • 如果您想访问响应正文,则需要包装响应并在写入响应正文时缓冲响应正文,以便以后检索

ContentCaching*Wrapper 类在 WebFlux 中不存在,但您可以创建类似的类.但请记住这里的其他要点:

ContentCaching*Wrapper classes don't exist in WebFlux but you could create similar ones. But keep in mind other points here:

  • 在内存中缓冲数据在某种程度上违背了反应式堆栈,因为我们试图在那里非常有效地利用可用资源
  • 您不应该篡改实际的数据流并且刷新频率高于/低于预期,否则您可能会破坏流式传输用例
  • 在那个级别,您只能访问 DataBuffer 实例,这些实例(大致上)是内存高效的字节数组.那些属于缓冲池并被回收用于其他交换.如果这些没有正确保留/释放,则会造成内存泄漏(并且缓冲数据以供以后使用当然适合这种情况)
  • 再次在那个级别,它只是字节,您无权访问任何编解码器来解析 HTTP 正文.如果内容不是人类可读的,我会忘记缓冲内容
  • buffering data in memory somehow goes against the reactive stack, since we're trying there to be very efficient with the available resources
  • you should not tamper with the actual flow of data and flush more/less often than expected, otherwise you'd risk breaking streaming uses cases
  • at that level, you only have access to DataBuffer instances, which are (roughly) memory-efficient byte arrays. Those belong to buffer pools and are recycled for other exchanges. If those aren't properly retained/released, memory leaks are created (and buffering data for later consumption certainly fits that scenario)
  • again at that level, it's only bytes and you don't have access to any codec to parse the HTTP body. I'd forget about buffering the content if it's not human-readable in the first place

您问题的其他答案:

  • 是的,WebFilter 可能是最好的方法
  • 不,您不应该订阅请求正文,否则您将使用处理程序无法读取的数据;你可以在doOn操作符
  • flatMap请求和缓冲数据
  • 包装响应应该可以让您访问正在写入的响应主体;但是不要忘记内存泄漏
  • yes, the WebFilter is probably the best approach
  • no, you shouldn't subscribe to the request body otherwise you'd consume data that the handler won't be able to read; you can flatMap on the request and buffer data in doOn operators
  • wrapping the response should give you access to the response body as it's being written; don't forget about memory leaks, though

这篇关于如何在 Spring WebFlux 中记录请求和响应主体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆