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

在quarkus-resteasy-reactive中如何在服务响应过滤器中记录请求体

Quarkus ServerResponseFilter 记录请求体正确实现方案

错误原因

你当前遇到的类转换异常,是因为Quarkus Resteasy Reactive在响应过滤器中注入的ContainerRequestContext实际是PreventAbortResteasyReactiveContainerRequestContext包装类,和QuarkusResteasyReactiveRequestContext无继承关系,强转自然会失败。同时请求体默认仅可被消费一次,若未提前缓存,响应阶段也可能无法读取到请求体内容。


解决方案

方案1:直接注入QuarkusResteasyReactiveRequestContext(最简实现)

不需要从ContainerRequestContext强转,直接将QuarkusResteasyReactiveRequestContext作为响应过滤器方法的入参,Quarkus会自动注入正确的上下文实例:

import io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext;
import io.smallrye.mutiny.Uni;
import org.jboss.resteasy.reactive.server.ServerResponseFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;

public class CustomResponseFilter {
    private static final Logger logger = LoggerFactory.getLogger(CustomResponseFilter.class);

    @ServerResponseFilter
    public Uni<Void> filter(ContainerRequestContext request, ContainerResponseContext response, QuarkusResteasyReactiveRequestContext reactiveCtx) {
        logger.info("请求体内容:{}", reactiveCtx.getRequestEntity());
        return Uni.createFrom().nullItem();
    }
}

注意:该方法拿到的是已经完成反序列化的请求体对象,如果你需要原始字符串格式的请求体,使用方案2


方案2:搭配请求过滤器缓存原始请求体

如果需要获取未反序列化的原始请求体字符串,需要先在请求过滤器中缓存请求体流副本,避免流被消费后业务逻辑无法读取:

  1. 先实现请求过滤器缓存请求体
import org.jboss.resteasy.reactive.server.ServerRequestFilter;
import org.apache.commons.io.IOUtils;
import java.nio.charset.StandardCharsets;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.ext.Provider;
import java.io.ByteArrayInputStream;
import java.io.IOException;

@Provider
public class CustomRequestFilter {
    @ServerRequestFilter
    public void preFilter(ContainerRequestContext requestContext) throws IOException {
        // 读取原始请求体
        String requestBody = IOUtils.toString(requestContext.getEntityStream(), StandardCharsets.UTF_8);
        // 把请求体存入请求属性
        requestContext.setProperty("rawRequestBody", requestBody);
        // 把请求体流写回去,不影响后续业务逻辑读取
        requestContext.setEntityStream(new ByteArrayInputStream(requestBody.getBytes(StandardCharsets.UTF_8)));
    }
}
  1. 响应过滤器直接读取缓存的请求体
import io.smallrye.mutiny.Uni;
import org.jboss.resteasy.reactive.server.ServerResponseFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;

public class CustomResponseFilter {
    private static final Logger logger = LoggerFactory.getLogger(CustomResponseFilter.class);

    @ServerResponseFilter
    public Uni<Void> filter(ContainerRequestContext request, ContainerResponseContext response) {
        String requestBody = (String) request.getProperty("rawRequestBody");
        if (requestBody != null) {
            logger.info("原始请求体:{}", requestBody);
        }
        return Uni.createFrom().nullItem();
    }
}

注意事项

  • 大体积请求体(如文件上传)不要全量缓存/打印,避免触发OOM
  • 如果项目配置了请求体读取阈值,超过阈值的请求体不会自动存入getRequestEntity(),需要自行处理流的缓存
  • 若存在请求体加密、压缩的场景,需要先解密/解压后再记录

内容的提问来源于stack exchange,提问作者AmsterdamLuis

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 22:27:04