You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何记录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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 01:34:56