如何记录Quarkus SmallRye GraphQL的响应体?
如何在Quarkus SmallRye GraphQL中记录后端返回的GraphQL响应体
我使用Quarkus SmallRye GraphQL实现了一个后端API,需要记录后端返回给客户端的GraphQL响应体。已知HTTP访问日志无法记录响应体,尝试通过Vert.X路由过滤器拦截请求和响应,请求日志可以正常输出,但无法获取到响应体。
现有代码示例:
@Slf4j public class LiquidoRequestLogger { @RouteFilter(100) void myLogFilter(RoutingContext ctx) { // ========== 记录请求 log.debug("=> {} {}", countPadded, ctx.request().method(), ctx.request().absoluteURI()); // ========= 记录响应状态码 log.debug("<=[Wrapper]= [{}] {}", countPadded, ctx.response().getStatusCode()); // <====== 如何在这里记录响应体? ctx.next(); } }
核心原因
你的路由过滤器执行时,响应体还未生成——GraphQL的响应是在后续的路由处理逻辑中才会写入到响应流里,所以直接在过滤器中读取响应体是拿不到内容的。需要通过监听响应的生命周期事件,或者启用响应体缓存来获取最终的响应内容。
方法一:使用Vert.X BodyHandler缓存响应体
Vert.X的BodyHandler可以帮你缓存响应体,之后就能在响应结束时获取完整的响应内容。修改你的过滤器如下:
@Slf4j public class LiquidoRequestLogger { @RouteFilter(100) void myLogFilter(RoutingContext ctx) { // 1. 绑定响应体处理回调,响应写入完成后触发 ctx.response().bodyHandler(bodyBuffer -> { String responseBody = bodyBuffer.toString(); log.debug("<=[Response Body]= [{}] {}", ctx.response().getStatusCode(), responseBody); }); // 2. 记录请求信息 log.debug("=> {} {}", ctx.request().method(), ctx.request().absoluteURI()); // 3. 继续执行后续路由逻辑 ctx.next(); } }
方法二:通过包装响应输出流获取响应体
如果不想依赖BodyHandler,也可以通过包装响应的writeHandler来捕获输出的内容:
@Slf4j public class LiquidoRequestLogger { @RouteFilter(100) void myLogFilter(RoutingContext ctx) { // 保存原始的写入处理器 Handler<Buffer> originalWriteHandler = ctx.response().getWriteHandler(); StringBuilder responseBodyBuilder = new StringBuilder(); // 包装写入处理器,捕获每一段输出的响应内容 ctx.response().setWriteHandler(buffer -> { responseBodyBuilder.append(buffer.toString()); // 调用原始处理器,保证响应正常发送给客户端 originalWriteHandler.handle(buffer); }); // 监听响应结束事件,输出完整响应体 ctx.response().endHandler(v -> { String responseBody = responseBodyBuilder.toString(); log.debug("<=[Response Body]= [{}] {}", ctx.response().getStatusCode(), responseBody); }); // 记录请求信息 log.debug("=> {} {}", ctx.request().method(), ctx.request().absoluteURI()); ctx.next(); } }
注意事项
- 路由过滤器的优先级(
@RouteFilter(100))要设置合理,确保它在SmallRye GraphQL的路由处理逻辑之前执行。 - 如果响应体是二进制数据(比如文件),需要调整处理逻辑(避免直接转成字符串)。
- 生产环境中建议限制响应体日志的输出场景(比如只记录特定接口、或者对大响应体做截断),避免占用过多日志存储空间。
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

