Jersey / JAX-RS:在响应头中返回Content-Length而不是chunked transfer encoding

时间:2012-07-25 22:03:41

标签: java rest jaxb jersey jax-rs

我正在使用Jersey创建RESTful API资源,并使用ResponseBuilder来生成响应。

RESTful资源的示例代码:

public class infoResource{
  @GET
  @Path("service/{id}")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public Response getCompany(@PathParam("id")String id) {
      //company is just a POJO.
      Company company = getCompany(id);
      return Response.status(200).entity(company).build();  
  }
}

在响应中,它在响应头中返回分块传输编码。 “泽西世界”中有什么方法让它在响应头中返回Content-Length标题而不是Transfer-Encoding: chunked标题?

4 个答案:

答案 0 :(得分:5)

选择Content-LengthTransfer-Encoding只是容器的选择。这实际上是缓冲区大小的问题。

一种可能的解决方案是提供SevletFilter缓冲所有那些编组的字节并设置Content-Length标头值。

请参阅this page

@WebFilter
public class BufferFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
        throws IOException, ServletException {

        final ByteArrayOutputStream buffer =
            new ByteArrayOutputStream();

        // prepare a new ServletResponseWrapper
        // which returns the buffer as its getOutputStream();

        chain.doFilter(...)

        // now you know how exactly big is your response.

        final byte[] responseBytes = buffer.toByteArray();
        response.setContentLength(responseBytes.length);
        response.getOutputStream().write(responseBytes);
        response.flush();
    }

    @Override
    public void destroy() {
    }
}

答案 1 :(得分:3)

在扩展ResourceConfig的类中,您可以设置缓冲区大小。超过此大小的回复将被分块,下面将有Content-Length。

public class ApplicationConfig extends ResourceConfig {

  public ApplicationConfig() {
    //your initialization
    property(CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER, 2000000); 
  }
}

答案 2 :(得分:2)

例如,如果您的输入流是从本地文件系统读取的,那么就是 添加:

response.header( "Content-Length", file.length() );

检查完整代码以获得更清晰的解释:

@Path("/files")
public class FileDownloadService {

    private static final String TXT_FILE = "C:\\your file";    
    @GET
    @Path("/txt")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getTextFile() throws IOException {
        File file = new File(TXT_FILE);
        FileInputStream inStream = new FileInputStream(file);
        ResponseBuilder response = Response.ok((Object) inStream);
        response.header("Content-Disposition", "attachment; filename=\"filename\"");
        response.header( "Content-Length", file.length() );
        return response.build();
    }  
}

客户端是Apache HttpClient代码。

答案 3 :(得分:0)

StackOverflow上一个非常相似的问题的答案可以be found here

我在这里复制它以确保它没有转换为注释:

用于执行此操作的优秀示例过滤器,可以从项目中单独使用,来自github上this ContentLengthFilter.java项目的Carrot2

请注意,使用带有字节流的响应包装器来解决问题,因此这也可以确保过滤器链中的某些其他过滤器/代码不会设置Transfer-Encoding: Chunked,并覆盖您的{{1它设置时的标题。您可以通过使用较大的文件对其进行测试来验证这一点,因为它们通常会在响应中进行分块。

我也会在这里复制文件的内容,以确保它不会成为断开的链接:

Content-Length