在某些情况下,您的REST api会提供非常长的响应,我们都知道移动设备/网络上的传输速度和带宽仍然非常重要。 我认为这是开发支持移动应用程序的REST api时需要解决的第一个性能优化点。 你猜怎么了? 因为响应是文本,所以我们可以压缩它们。 借助当今智能手机和平板电脑的强大功能,在客户端上解压缩它们并不是什么大不了的事。因此,在本文中,我将介绍如何使用泽西岛(Jersey)在Java中构建压缩REST API响应的方法。是JAX-RS参考实现(以及更多)…
1.球衣过滤器和拦截器
好吧,得益于Jersey强大的过滤器和拦截器功能,实现起来相当容易。 过滤器主要用于操纵请求和响应参数,例如HTTP头,URI和/或HTTP方法,而拦截器则用于通过操纵实体输入/输出流来操纵实体。
您已经在我的帖子中看到了过滤器的功能:
- 如何使用Jersey来在Java的服务器端添加CORS支持 ,在此我展示了如何CORS启用REST API
和 - 如何使用SLF4J和Logback登录Spring ,在这里我展示了如何记录来自REST API的请求和响应
但要进行压缩,将使用GZip WriterInterceptor
。 Writer拦截器用于将实体写入“线路”的情况,在这种情况下,在服务器端,这意味着写出响应实体时。
GZip作家拦截器
因此,让我们看一下我们的GZip Writer拦截器:
GZip作家拦截器
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 {@Overridepublic void aroundWriteTo(WriterInterceptorContext context)throws IOException, WebApplicationException {MultivaluedMap<String,Object> headers = context.getHeaders();headers.add("Content-Encoding", "gzip");final OutputStream outputStream = context.getOutputStream();context.setOutputStream(new GZIPOutputStream(outputStream));context.proceed();}
}
注意:
- 它实现了
WriterInterceptor
,它是消息正文WriterInterceptor
器拦截器的接口,该拦截器包装了对javax.ws.rs.ext.MessageBodyWriter.writeTo
调用。 - 实现
WriterInterceptor
合同的提供程序必须在JAX-RS运行时中以编程方式注册,或者必须使用@Provider批注进行注释,以在提供程序扫描阶段由JAX-RS运行时自动发现。 -
@Compress
是名称绑定批注,我们将在下一段中对其进行详细讨论 - “拦截器从WriterInterceptorContext获取输出流,并设置一个新流,它是原始输出流的GZIP包装器。 执行完所有拦截器后,最后设置为WriterInterceptorContext的输出流将用于实体的序列化。 在上面的示例中,实体字节将被写入GZIPOutputStream,它将压缩流数据并将其写入原始输出流。 原始流始终是将数据写入“电线”的流。 在服务器上使用拦截器时,原始输出流是将数据写入基础服务器容器流的流,该服务器容器流将响应发送到客户端。 [2]
- “ WriteTo()的重写方法将WriterInterceptorContext作为参数。 此上下文包含标头参数,请求属性,实体,实体流和其他属性的获取器和设置器。” [2]; 压缩响应时,应将“ Content-Encoding”标头设置为“ gzip”
压缩注释
过滤器和拦截器可以绑定名称 。 名称绑定是一个概念,它允许对JAX-RS运行时说,仅针对特定的资源方法才执行特定的过滤器或拦截器。 当过滤器或拦截器仅限于特定的资源方法时,我们说它是名称绑定的 。 没有这种限制的过滤器和拦截器称为global 。 在我们的案例中,我们构建了@Compress批注:
压缩注释
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 {}
并用它来标记应该压缩的资源上的方法( 例如,使用PodcastsResource
获取所有播PodcastsResource
):
@Compress资源方法上的注释用法
@Component
@Path("/podcasts")
public class PodcastsResource {@Autowiredprivate PodcastService podcastService;.........................../** *********************************** READ ************************************//*** Returns all resources (podcasts) from the database* * @return* @throws IOException* @throws JsonMappingException* @throws JsonGenerationException* @throws AppException*/@GET@Compress@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })public List<Podcast> getPodcasts(@QueryParam("orderByInsertionDate") String orderByInsertionDate,@QueryParam("numberDaysToLookBack") Integer numberDaysToLookBack)throws IOException, AppException {List<Podcast> podcasts = podcastService.getPodcasts(orderByInsertionDate, numberDaysToLookBack);return podcasts;}...........................
}
2.测试
SOAPui
好吧,如果您正在使用SOAPui进行测试,则可以针对PodcastsResource
发出以下请求。
请求:
要求范例
GET http://localhost:8888/demo-rest-jersey-spring/podcasts/?orderByInsertionDate=DESC HTTP/1.1
Accept-Encoding: gzip,deflate
Accept: application/json, application/xml
Host: localhost:8888
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
响应:
GZipped json响应,由SOAPui自动解压缩
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Content-Length: 409
Server: Jetty(9.0.7.v20131107)[{"id": 2,"title": "Quarks & Co - zum Mitnehmen","linkOnPodcastpedia": "http://www.podcastpedia.org/quarks","feed": "http://podcast.wdr.de/quarks.xml","description": "Quarks & Co: Das Wissenschaftsmagazin","insertionDate": "2014-10-29T10:46:13.00+0100"},{"id": 1,"title": "- The Naked Scientists Podcast - Stripping Down Science","linkOnPodcastpedia": "http://www.podcastpedia.org/podcasts/792/-The-Naked-Scientists-Podcast-Stripping-Down-Science","feed": "feed_placeholder","description": "The Naked Scientists flagship science show brings you a lighthearted look at the latest scientific breakthroughs, interviews with the world top scientists, answers to your science questions and science experiments to try at home.","insertionDate": "2014-10-29T10:46:02.00+0100"}
]
SOAPui可以识别Content-Type: gzip
标头(已添加到GZIPWriterInterceptor
并自动解压缩响应并将其显示为人眼可读。
好吧,就是这样。 您已经了解到Jersey如何直接压缩REST api响应。
提示:如果您真的想学习如何在Java中设计和实现REST API,请阅读以下教程–借助Jersey和Spring在Java中进行REST API设计和实现
翻译自: https://www.javacodegeeks.com/2014/11/how-to-compress-responses-in-java-rest-api-with-gzip-and-jersey.html