如何在java REST API中用GZip和Jersey压缩相应

2025-05-16 11:52:38
推荐回答(1个)
回答1:

有许多情景当你的REST api提供的相应是非常长的,并且都知道传递速度和贷款在移动设备/网络上是多重要。当开发支持REST apis的移动app的时候,首要的性能最优化的点就是需要解决。猜猜是什么?因为响应式文本,因此能压缩这些文本。而且随着当前的只能手机和平板的能力,在客户端解压文本应该不是个大问题...因此在这篇文章中,如果你使用java的Jersey构建它,将介绍你怎么能有选择性的压缩REST API响应,这个Jersey事JAX-RS的映射实现(还有更多)...

  1.Jersey过滤器和拦截器

  啊,感谢Jersey的强大的过滤器和拦截器特性,这个实现是相当容易的。然后过滤器是主要打算来维护像HTTP headers,URIs和/或HTTP methods的request和response的参数,拦截器是维护实体,通过维护实体的输入/输出流。

  但是对于压缩将使用一个GZip WriterInterceptor,一个写拦截器被用于这种情况,在那个类里,实体被写到"wire",当在这种情况中时,它在服务器这边,这就意味着输出一个响应实体。

  1.1GZip Writer Interceptor

  那来看看GZip Writer Interceptor吧:

  GZip Writer Interceptor

  package org.codingpedia.demo.rest.interceptors;

  import java.io.IOException;

  import java.io.OutputStream;

  import java.util.zip.GZIPOutputStream;

  import javax.ws.rs.WebApplicationException;

  import javax.ws.rs.core.MultivaluedMap;

  import javax.ws.rs.ext.WriterInterceptor;

  import javax.ws.rs.ext.WriterInterceptorContext;

  @Provider

  @Compress

  public class GZIPWriterInterceptor implements WriterInterceptor {

  @Override

  public void aroundWriteTo(WriterInterceptorContext context)

  throws IOException, WebApplicationException {

  MultivaluedMap headers = context.getHeaders();

  headers.add("Content-Encoding", "gzip");

  final OutputStream outputStream = context.getOutputStream();

  context.setOutputStream(new GZIPOutputStream(outputStream));

  context.proceed();

  }

  }

  注意:

  它实现了WriterInterceptor,这是一个写拦截器的消息体的接口,这个接口包装调用javax.ws.rs.ext.MessageBodyWriter.writeTo

  供应商实现WriterInterceptor协议必须要么以编程方式注册进一个JAX-RS运行环境,要么必须用@Provider注解来注解在一个提供商扫描语句期间自动的被JAX-RS运行环境发现。

  @Compress是绑定注解的名称,在接下来的段落中将更详细的讨论它

  “拦截器从WriterInterceptorContext中获得一个输出流并且设置一个新的用原始的GZIP包装器包装的输出流。在所有的拦截器被执行以后,输出流最终设置WriterInterceptorContext将用于序列化实体。在上面的例子中,实体字节将被写到GZIPOutputStream中,这个类将压缩流数据,然后把他们写到原始输出流。原始流总是把数据写到wire中。当拦截器被用在服务器上时,原始输出流会把数据写到底层服务器容器的流中,然后发送响应给客户端。”

  “重载方法aroundWriteTo()获取WriterInterceptorContextz作为参数。这个上下文包括请求头参数getters和setters,请求属性,实体,实体流和其它属性;当你压缩你的响应时,你应当设置'Content-Encoding'头位gzip”

  1.2 压缩注解

  过滤器和拦截器能被绑定名字。名称绑定是一种概念,这种概念就是允许告诉一个JAX-RS的运行时,一个只为特定资源方法的特定的过滤器或者拦截器将被执行。当一个过滤器或者拦截器只对一些特定的资源方法限制,那我们就认为它是名称绑定。过滤器和拦截器没有这样的限制就被称作global。在我们的例子中我们已经构建了@Compress注解:

  Compress annotation

  package org.codingpedia.demo.rest.interceptors;

  import java.lang.annotation.Retention;

  import java.lang.annotation.RetentionPolicy;

  import javax.ws.rs.NameBinding;

  //@Compress annotation is the name binding annotation

  @NameBinding

  @Retention(RetentionPolicy.RUNTIME)

  public @interface Compress {}

  而且用它来标记在资源上的方法,这个方法应该是被压缩的(eg:当GET-ing的时候,所有的博客用PodcastsResource)

  @Compress annotation在资源方法上的使用

  @Component

  @Path("/podcasts")

  public class PodcastsResource {

  @Autowired

  private PodcastService podcastService;