Last active
July 19, 2023 20:19
-
-
Save leifoolsen/2daf9749a3d89e9cab97 to your computer and use it in GitHub Desktop.
JAX-RS 2: How to compress response if client accepts gzip; "Accept-Encoding: gzip, deflate, sdch"
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Create a WriterInterceptor, | |
// see: https://jersey.java.net/documentation/latest/user-guide.html#d0e9728 | |
import ... | |
@Provider | |
public class GZIPWriterInterceptor implements WriterInterceptor { | |
private final Logger logger = LoggerFactory.getLogger(getClass()); | |
private HttpHeaders httpHeaders; | |
public GZIPWriterInterceptor(@Context @NotNull HttpHeaders httpHeaders) { | |
this.httpHeaders = httpHeaders; | |
} | |
@Override | |
public void aroundWriteTo(WriterInterceptorContext context) | |
throws IOException, WebApplicationException { | |
MultivaluedMap<String,String> requestHeaders = httpHeaders.getRequestHeaders(); | |
List<String> acceptEncoding = MoreObjects.firstNonNull( | |
requestHeaders.get(HttpHeaders.ACCEPT_ENCODING), new ArrayList<String>()); | |
// Compress if client accepts gzip encoding | |
for (String s : acceptEncoding) { | |
if(s.contains("gzip")) { | |
logger.debug("GZIP'ing response"); | |
MultivaluedMap<String, Object> headers = context.getHeaders(); | |
headers.add(HttpHeaders.CONTENT_ENCODING, "gzip"); | |
//com.google.common.net.MediaType.GZIP); | |
final OutputStream outputStream = context.getOutputStream(); | |
context.setOutputStream(new GZIPOutputStream(outputStream)); | |
break; | |
} | |
} | |
context.proceed(); | |
} | |
} | |
// If we're using the client api, then we need a ReaderInterceptor as well | |
import ... | |
public class GZIPReaderInterceptor implements ReaderInterceptor { | |
private final Logger logger = LoggerFactory.getLogger(getClass()); | |
@Override | |
public Object aroundReadFrom(ReaderInterceptorContext context) | |
throws IOException, WebApplicationException { | |
MultivaluedMap<String,String> headers = context.getHeaders(); | |
List<String> contentEncoding = MoreObjects.firstNonNull( | |
headers.get(HttpHeaders.CONTENT_ENCODING), new ArrayList<String>()); | |
for (String s : contentEncoding) { | |
if(s.contains("gzip")) { | |
logger.debug("Decompressing GZIP"); | |
final InputStream originalInputStream = context.getInputStream(); | |
context.setInputStream(new GZIPInputStream(originalInputStream)); | |
break; | |
} | |
} | |
return context.proceed(); | |
} | |
} | |
// Register ReaderInterceptor on client-api | |
@BeforeClass | |
public static void startServer() throws Exception { | |
// Start the server | |
// ... Code ommited for brewety | |
// Create the client | |
Client c = ClientBuilder.newClient(); | |
// Client interceptor to deflate GZIP'ed content on client side | |
c.register(GZIPReaderInterceptor.class); | |
target = c.target(server.getURI()).path(JerseyJpaApp.APPLICATION_PATH); | |
} | |
// Set header(HttpHeaders.ACCEPT_ENCODING, "gzip") in request | |
@Test | |
public void getBookByIsbnShouldReturn_OK() { | |
final Response response = target | |
.path(BookResource.RESOURCE_PATH) | |
.path(ISBN_TRAVELING_TO_INFINITY) | |
.request(MediaType.APPLICATION_JSON_TYPE) | |
.header(HttpHeaders.ACCEPT_ENCODING, "gzip") | |
.get(); | |
assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); | |
List<Object> objects = response.getHeaders().get("Content-Encoding"); | |
assertNotNull(objects); | |
assertThat(objects.toString(), containsString("gzip")); | |
} | |
// That's it :-) | |
// If you're sending request from a browser then | |
// set "Accept-Encoding: gzip, deflate, sdch" before sending request | |
// Note: this is the default setting in Chrome (I think) |
Basically same code as found here: https://jersey.java.net/documentation/latest/user-guide.html#d0e9728. We can extend further and combine HttpHeaders.CONTENT_ENCODING with the @compress annotation to compress only when request method is annotated with @compress. In this way we can return compressed content given that the client accepts gzip and response method is annotated with @compress
After the call to proceed(), the GZIP stream must be explicitly closed (at least in Java-SE 1.8), or there will be no output.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
What about http://www.codingpedia.org/ama/how-to-compress-responses-in-java-rest-api-with-gzip-and-jersey/