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

如何在Jersey中用输入流实体返回带Content-Length的非分块编码响应

根因说明

Jersey默认处理InputStream类型的响应实体时,自带的InputStream MessageBodyWriter会默认返回流长度为-1,此时Jersey会判定响应总长度未知,不管你手动设置了什么Content-Length头,都会自动启用分块传输编码,同时覆盖你手动设置的Content-Length头。

解决方案1:用官方API指定响应长度(最简单)

不要手动通过header()方法设置Content-Length,改用ResponseBuilder自带的contentLength()方法设置长度,Jersey会识别该值并跳过分块逻辑:

@GET
@Path("/contentLength")
public Response contentLength() {
    final int contentLen = 10_000;
    return Response.ok()
            .contentLength(contentLen)
            .entity(RandomInputStream.generateBytes(contentLen))
            .build();
}

解决方案2:自定义已知长度的InputStream处理器(适合大体积流、无缓冲)

如果方案1不生效(多见于低版本Jersey、或者有自定义的响应处理逻辑),可以通过自定义MessageBodyWriter的方式实现零缓冲的非分块响应:

  1. 首先定义带长度的InputStream包装类
public class KnownLengthInputStream extends FilterInputStream {
    private final long contentLength;

    public KnownLengthInputStream(InputStream in, long contentLength) {
        super(in);
        this.contentLength = contentLength;
    }

    public long getContentLength() {
        return contentLength;
    }
}
  1. 自定义对应的MessageBodyWriter并注册到Jersey
@Provider
@Produces(MediaType.WILDCARD)
public class KnownLengthInputStreamWriter implements MessageBodyWriter<KnownLengthInputStream> {
    @Override
    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return KnownLengthInputStream.class.isAssignableFrom(type);
    }

    @Override
    public long getSize(KnownLengthInputStream inputStream, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        // 返回已知的流长度,Jersey会自动设置Content-Length头,不启用分块
        return inputStream.getContentLength();
    }

    @Override
    public void writeTo(KnownLengthInputStream inputStream, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
        // 边读边写,无额外内存缓冲,可自定义缓冲区大小
        byte[] buffer = new byte[8192];
        int read;
        while ((read = inputStream.read(buffer)) != -1) {
            entityStream.write(buffer, 0, read);
        }
        inputStream.close();
    }
}
  1. 修改资源方法使用自定义类
@GET
@Path("/contentLength")
public Response contentLength() {
    final int contentLen = 10_000;
    InputStream rawStream = RandomInputStream.generateBytes(contentLen);
    KnownLengthInputStream stream = new KnownLengthInputStream(rawStream, contentLen);
    return Response.ok(stream).build();
}

两个方案都不会对响应做全量缓冲,完全符合大体积响应的使用要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 05:36:03