在Jersey JAX-RS服务器中返回大型对象时,如何设置内容长度

在Jersey JAX-RS服务器中返回大型对象时,如何设置内容长度,jersey,jax-rs,jersey-2.0,Jersey,Jax Rs,Jersey 2.0,有时,我希望返回一个大的(数MB)二进制对象作为JAX-RS资源方法的响应。我知道对象的大小,我希望在响应上设置内容长度头,我不希望使用分块传输编码 在Jersey 1.x中,我通过自定义MessageBodyWriter解决了这个问题: public class Blob { public InputStream stream; public long length; } @Provider public class BlobWriter extends MessageBod

有时,我希望返回一个大的(数MB)二进制对象作为JAX-RS资源方法的响应。我知道对象的大小,我希望在响应上设置内容长度头,我不希望使用分块传输编码

在Jersey 1.x中,我通过自定义MessageBodyWriter解决了这个问题:

public class Blob {
  public InputStream stream;
  public long length;    
}

@Provider
public class BlobWriter extends MessageBodyWriter<Blob> {

  public boolean isWriteable(Class<?> type, Type genericType,
                               Annotation[] annotations, MediaType mediaType) {
    return Blob.class.isAssignableFrom(type);
  }

  public long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations,
                        MediaType mediaType) {
    return t.length;
  }

  public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,
                      MediaType mediaType,
                      MultivaluedMap<String, Object> httpHeaders,
                      OutputStream entityStream)
            throws java.io.IOException {
    org.glassfish.jersey.message.internal.ReaderWriter.writeTo(t.stream, entityStream);
  }
}
公共类Blob{
公共输入流;
公共长线;
}
@提供者
公共类BlobWriter扩展MessageBodyWriter{
公共布尔值可写(类类型、类型genericType、,
注释[]注释,MediaType(MediaType){
返回Blob.class.isAssignableFrom(类型);
}
公共长getSize(T,类类型,类型genericType,注释[]注释,
媒体类型(媒体类型){
返回t.length;
}
public void writeTo(T,类类型,类型genericType,注释[]注释,
MediaType MediaType,
多值MAP HttpHeader,
OutputStream(实体流)
抛出java.io.IOException{
org.glassfish.jersey.message.internal.ReaderWriter.writeTo(t.stream,entityStream);
}
}
但当我升级到Jersey 2.x时,这就停止了工作,因为JAX-RS/Jersey 2不再关心MessageBodyWriter.getSize()。如何使用Jersey 2实现这一点?

来自:

从JAX-RS2.0开始,该方法已被弃用,其值 JAX-RS运行时将忽略该方法返回的值。全部的 建议MessageBodyWriter实现从 方法。负责计算实际内容长度标题 值已委托给JAX-RS运行时

JAX-RS实现还将决定是发送
内容长度
头还是
传输编码:分块

正如您已经知道的内容长度一样,您可以在ResourceClass中设置临时标题的长度,并在以下内容中设置真实标题:


似乎可以使用提供的httpHeaders从MessageBodyWriter.writeTo()设置内容长度头:

  public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,
                      MediaType mediaType,
                      MultivaluedMap<String, Object> httpHeaders,
                      OutputStream entityStream)
            throws java.io.IOException {
    httpHeaders.addFirst(HttpHeaders.CONTENT_LENGTH, t.length.toString);
    org.glassfish.jersey.message.internal.ReaderWriter.writeTo(t.stream, entityStream);
  }
public void writeTo(T,类类型,类型genericType,注释[]注释,
MediaType MediaType,
多值MAP HttpHeader,
OutputStream(实体流)
抛出java.io.IOException{
httpHeaders.addFirst(httpHeaders.CONTENT\u LENGTH,t.LENGTH.toString);
org.glassfish.jersey.message.internal.ReaderWriter.writeTo(t.stream,entityStream);
}

我知道JAX-RS 2.0规范说了什么,这就是我的问题所在。我不想让Jersey为我做决定,我希望始终强制内容长度。添加带有额外缓冲的ServletFilter不是一个选项,因为响应可能非常大(数MB),缓冲会浪费内存。如果您知道大小,您应该能够将其存储在某个位置,并在ServletFilter中访问此信息。例如,在resource-class中设置一个
X-Content-Length
头。是的,这可能会起作用。然而,这似乎是一个过于复杂的解决方案。它还为您提供了对Servlet API不必要的依赖。必须有一个更简单、仅JAX-RS的解决方案。这是唯一有效的解决方案吗?这看起来很可笑。一个关于StackOverflow的类似问题的答案对我来说是否有效。设置Content-Length头会阻止JAX-RS隐式缓冲您的响应,这一点非常令人费解,但我不能对结果提出异议。
  public void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,
                      MediaType mediaType,
                      MultivaluedMap<String, Object> httpHeaders,
                      OutputStream entityStream)
            throws java.io.IOException {
    httpHeaders.addFirst(HttpHeaders.CONTENT_LENGTH, t.length.toString);
    org.glassfish.jersey.message.internal.ReaderWriter.writeTo(t.stream, entityStream);
  }