如何在JAX-RS中提供已经gzipped的内容?

时间:2015-04-15 14:56:01

标签: java jax-rs gzip resteasy content-encoding

我正在使用Resteasy开发一个小型JAX-RS应用程序。我希望应用程序为Javascript和CSS文件等提供一些静态内容。我想利用webjars.org的jar中打包的资源的已经gzip压缩版本。因此,我需要处理Accept-Encoding标头并检查.gz是否存在。

到目前为止,我所拥有的是:

@Path("res/{path:.*}")
@GET
public Response webjars(@PathParam("path") String path, @HeaderParam("Accept-Encoding") String acceptEncoding) {

    // Guesses MIME type from the path extension elsewhere.
    String mime = mimes.getContentType(path);

    if (acceptEncoding.contains("gzip")) {
        InputStream is = getClass().getResourceAsStream("/META-INF/resources/webjars/" + path + ".gz");
        if (is != null)
            return Response.ok().type(mime).encoding("gzip").entity(is).build();
    }

    InputStream is = getClass().getResourceAsStream("/META-INF/resources/webjars/" + path);
    if (is != null)
        return Response.ok().type(mime).entity(is).build();

    return Response.status(Status.NOT_FOUND).build();
}

但它不起作用。所提供的内容完全被打破。到目前为止,我发现了一个再次压缩流的组件:org.jboss.resteasy.plugins.interceptors.encoding.GZIPEncodingInterceptor,因为我手动填充了Content-Encoding标头(使用ResponseBuilder.encoding方法)。

这看起来像是一个错误,因为显然,没有办法共享已经gzipped的流。但是,使用JAX-RS可以实现吗?这是一个Resteasy错误吗?

我可以想到在Resteasy外部实现相同功能的各种方法,比如映射webjars.org servlet(我不在Servlet API 3.0环境中,所以我没有META-INF/resources/自动类路径映射)。尽管如此,我的问题仍然存在。它适用于其他几种情况。

更新

我已填写问题RESTEASY-1170

1 个答案:

答案 0 :(得分:2)

以上是我上述评论的示例实现。

  

我要说的是,如果您不希望它被当前拦截器处理,请不要设置标头,创建一个名称绑定的拦截器,使用您自己的注释,并设置优先级低于您想要避免的优先级,然后在拦截器中设置标题...

@AlreadyGzipped

@NameBinding
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface AlreadyGzipped {}

WriterInterceptor。请注意@PriorityGZIPEncodingInterceptor使用Priorities.ENTITY_CODER

@Provider
@AlreadyGzipped
@Priority(Priorities.ENTITY_CODER + 1000)
public class AlreadyGzippedWriterInterceptor implements WriterInterceptor {
    @Context HttpHeaders headers;

    @Override
    public void aroundWriteTo(WriterInterceptorContext wic) throws IOException, 
                                                      WebApplicationException {
        String header = headers.getHeaderString("Accept-Encoding");
        if (null != header && header.equalsIgnoreCase("gzip")) {
            wic.getHeaders().putSingle("Content-Encoding", "gzip");
        }
        wic.proceed();
    }  
}

测试资源

@Path("resource")
public class AlreadyGzippedResoure {

    @GET
    @AlreadyGzipped
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getAlreadGzipped() throws Exception {
        InputStream is = getClass().getResourceAsStream("/stackoverflow.png.gz");
        return Response.ok(is).build();
    }
}

测试

public class Main {
    public static void main(String[] args) throws Exception {
        Client client = ClientBuilder.newClient();
        String url = "http://localhost:8080/api/resource";

        Response response = client.target(url).request().acceptEncoding("gzip").get();
        Image image = ImageIO.read(response.readEntity(InputStream.class));
        JOptionPane.showMessageDialog(null,new JLabel(new ImageIcon(image)));
    }
}

结果

enter image description here