java - 如何在 JAX-RS 中提供已压缩的内容?

标签 java jax-rs gzip resteasy content-encoding

我正在使用 Resteasy 开发一个小型 JAX-RS 应用程序。我希望应用程序为 Javascript 和 CSS 文件等提供一些静态内容,并且我想利用 webjars.org 的 jar 中打包的资源的已 gzip 版本。 。因此,我需要处理 Accept-Encoding header 并检查 .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 header (使用 ResponseBuilder.encoding 方法)。

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

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

更新:

为了记录,我已经填写了问题 RESTEASY-1170 .

最佳答案

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

The point I'm getting at is that if you don't want it to be handle by the current interceptor, don't set the header, create an Interceptor that will be name binded, with your own annotation, and set the priority to one lower than the one you want to avoid, then set the header in your Interceptor...

@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

关于java - 如何在 JAX-RS 中提供已压缩的内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29653641/

相关文章:

java - 泽西客户端 Xml 集合解码

java - 使用 JAX-RS 使用 JSON 字符串

bash - 将 tcpdump 输出写入压缩/gziped 文件

java - HTTPS 连接安卓

java - 父类中的 getter 和 setter

java - Spring Boot 中的自定义 JWE 过滤器阻止 CORS 选项请求

python - 将文本写入 gzip 文件

java - JSON 响应中的框字符

jaxb - 为什么在 Jersey 中使用 mime 类型 application/xml 请求资源时出现 "invalid request"?

javascript - Meteor Http 客户端 API 调用 Gzip 解压缩结果 JSON 不工作