如何在 Spring Webflux Java 中记录请求正文
Posted
技术标签:
【中文标题】如何在 Spring Webflux Java 中记录请求正文【英文标题】:How to log request body in spring Webflux Java 【发布时间】:2020-08-25 15:37:23 【问题描述】:我在 POST 请求中接收到一些 XML 有效负载,并希望看到收到的有效负载以进行调试。
下面(我的自定义 WebFilter)代码按预期记录 URI 和请求标头,但不记录请求正文/有效负载,我的反应代码一定有问题 -
final ServerHttpRequest request = exchange.getRequest();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
LOGGER.info("Request: uri=", request.getURI());
LOGGER.info("Request: headers=", request.getHeaders().entrySet());
request.getBody().doOnNext(dataBuffer ->
try
Channels.newChannel(baos).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
String body = new String(baos.toByteArray());
LOGGER.info("Request: payload=", body);
catch (IOException e)
e.printStackTrace();
finally
try
baos.close();
catch (IOException e)
e.printStackTrace();
);
我查看了 Brian 对下面帖子的回复并关注了它,但由于没有代码,我可能犯了一些愚蠢的错误
How to log request and response bodies in Spring WebFlux
更新代码
@Configuration
public class RequestFilter implements WebFilter
private static final Logger LOGGER = LoggerFactory.getLogger(RequestFilter.class);
@Override
@Order(Ordered.HIGHEST_PRECEDENCE)
public Mono<Void> filter(ServerWebExchange serverWebExchange,
WebFilterChain webFilterChain)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
serverWebExchange.getRequest().getBody().doOnNext(dataBuffer ->
try
Channels.newChannel(baos).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
String body = new String(baos.toByteArray());
LOGGER.info("Request: payload=", body);
catch (IOException e)
e.printStackTrace();
finally
try
baos.close();
catch (IOException e)
e.printStackTrace();
);
return webFilterChain.filter(serverWebExchange);
【问题讨论】:
你在这里打破链request.getBody().doOnNext( ...
@ThomasAndolf - 你的意思是我需要在 doOn 之前对其进行平面映射?谢谢!
不,我的意思是您似乎忽略了返回值***.com/a/61541336/1840146
所以如果我 doOnNext().subscribe() 我得到了所需的请求正文,但是就像你在上面提到的答案中解释的那样,我没有可用的数据供进一步使用。我已经多次浏览了您的帖子,但找不到放置“返回 Mono.empty()”的正确位置。谢谢!
好吧,你显然以前从未使用过 webflux。这不是命令式编程。您需要始终保持联系,您不能只写request.getBody().doOnNext( ...
而忽略响应。请制作一个可重复的小示例,以便我了解更大的图景。你的小代码 sn -p 不够用。
【参考方案1】:
除了将尸体提取到错误的位置之外,您做的部分正确。您必须在 ServerHttpRequestDecorator
实现中执行此操作,并将其插入到 WebFilter
实现中。
public class RequestLoggingDecorator extends ServerHttpRequestDecorator
private static final Logger LOGGER = LoggerFactory.getLogger(RequestLoggingDecorator.class);
public RequestLoggingDecorator(ServerHttpRequest delegate)
super(delegate);
@Override
public Flux<DataBuffer> getBody()
ByteArrayOutputStream baos = new ByteArrayOutputStream();
return super.getBody().doOnNext(dataBuffer ->
try
Channels.newChannel(baos).write(dataBuffer.asByteBuffer().asReadOnlyBuffer());
String body = new String(baos.toByteArray(), StandardCharsets.UTF_8);
LOGGER.info("Request: payload=", body);
catch (IOException e)
e.printStackTrace();
finally
try
baos.close();
catch (IOException e)
e.printStackTrace();
);
然后您可以在WebFilter
实现中配置它,如下所示:
@Configuration
public class RequestLoggingFilter implements WebFilter
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain)
ServerWebExchangeDecorator decorator =
new ServerWebExchangeDecorator(serverWebExchange)
@Override
public ServerHttpRequest getRequest()
return new RequestLoggingDecorator(serverWebExchange.getRequest());
;
return webFilterChain.filter(decorator);
这应该在每个传入的 Http 请求中记录您的请求正文。
【讨论】:
如何在不使用@Configuration
注释和自动配置的情况下以编程方式将这个 WebFilter
连接到 WebClient.Builder
中?以上是关于如何在 Spring Webflux Java 中记录请求正文的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring WebFlux 获取“身份验证”对象?
如何在 Spring boot 2 + Webflux + Thymeleaf 中配置 i18n?