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

JAX-RS LoggingFilter记录请求实体后流被消耗无法发送如何解决

问题原因

你直接读取StreamDataBodyPart的streamEntity流后,原流的读取指针已经走到末尾,后续请求发送时自然无法再读取到数据。clientRequest.enableBuffering()仅作用于整个请求实体的序列化缓存,不会处理FormDataMultiPart内部单个BodyPart的流,所以之前的方案无效。

解决方法

参考你处理响应时的思路,对需要读取内容的BodyPart流先做缓存,读取完日志后给BodyPart重新赋值新的可重复读的流即可,修改后的核心逻辑如下:

@Override
public void filter(ClientRequestContext requestContext) throws IOException {
    logger.trace(F_SEPARATOR);
    logger.trace(String.format(F_REQUEST, requestContext.getMethod(), requestContext.getUri()));
    requestContext.getHeaders()
                    .keySet()
                    .stream()
                    .sorted()
                    .forEach(key -> {
                        logger.trace(String.format(F_HEADER, key, requestContext.getHeaders().get(key)));
                    });
    if (requestContext.hasEntity()) {
        if(requestContext.getHeaders().get("Content-Type").get(0).toString().equals("multipart/form-data")) {
            FormDataMultiPart formDataMultiPart = (FormDataMultiPart) requestContext.getEntity();
            logger.trace(String.format(F_PART_NUMBER, formDataMultiPart.getBodyParts().size()));
            AtomicInteger index = new AtomicInteger(1);
            formDataMultiPart.getBodyParts().stream()
                    .forEach(bodyPart -> {
                        logger.trace(String.format(F_PART + F_PART_CONTENT_TYPE, index.get(), requestContext.getMediaType().toString()));
                        if(bodyPart.getMediaType().toString().equals("text/xml")) {
                            StreamDataBodyPart streamDataBodyPart = (StreamDataBodyPart) bodyPart;
                            try {
                                // 缓存流内容到字节数组
                                byte[] partBytes = IOUtils.toByteArray(streamDataBodyPart.getStreamEntity());
                                // 给bodyPart重新设置新的输入流,供后续请求发送使用
                                streamDataBodyPart.setStreamEntity(new ByteArrayInputStream(partBytes), StandardCharsets.UTF_8);
                                // 从缓存的字节数组读取内容打日志
                                String part = new String(partBytes, StandardCharsets.UTF_8);
                                logger.trace(String.format(F_PART + F_PART_CONTENT, index.get(), part));
                            } catch (IOException e) {
                                logger.error("读取formData part内容失败", e);
                            }
                        }
                        index.getAndIncrement();
                    });
        }
    }
    requestContext.setProperty(PROPERTY_NANOS, System.nanoTime());
}

注意事项

  • 上述代码依赖org.apache.commons.io.IOUtils工具类实现流转字节数组,如果你项目没有引入该依赖,可以自行实现流到字节数组的转换逻辑
  • 不同Jersey版本的StreamDataBodyPart.setStreamEntity方法参数可能略有差异,可根据你使用的版本调整参数即可,核心逻辑都是替换内部的流实例
  • 大体积的XML文件不建议打印日志,避免占用过多内存

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 19:48:02