如何在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的方式实现零缓冲的非分块响应:
- 首先定义带长度的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; } }
- 自定义对应的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(); } }
- 修改资源方法使用自定义类
@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
相关产品推荐
相关产品推荐

