Como compactar solicitações usando o Spring RestTemplate

Como compactar solicitações usando o Spring RestTemplate

1. Introdução

Neste breve tutorial, veremos como enviar solicitações HTTP contendo dados compactados.

Além disso, veremos como configurar um aplicativo da web Spring para que ele lide com solicitações compactadas.

2. Enviando solicitações compactadas

Em primeiro lugar, vamos criar um método que comprime uma matriz de bytes. Isso será útil em breve:

public static byte[] compress(byte[] body) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) {
        gzipOutputStream.write(body);
    }
    return baos.toByteArray();
}

Em seguida, precisamos implementar umClientHttpRequestInterceptor para modificar a solicitação. Observe que enviaremos os cabeçalhos de compressão HTTP apropriados e também chamaremos nosso método de compressão corporal:

public ClientHttpResponse intercept(HttpRequest req, byte[] body, ClientHttpRequestExecution exec)
  throws IOException {
    HttpHeaders httpHeaders = req.getHeaders();
    httpHeaders.add(HttpHeaders.CONTENT_ENCODING, "gzip");
    httpHeaders.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
    return exec.execute(req, compress(body));
}

Nosso interceptador pega o corpo da solicitação de saída e o compacta usando o formato GZIP. Neste exemplo, usamosGZIPOutputStream padrão de Java para fazer o trabalho para nós.

Além disso, devemos adicionar os cabeçalhos apropriados para a codificação de dados. Isso permite que o terminal final de destino saiba que está lidando com dados compactados por GZIP.

Finalmente, adicionamos o interceptor à nossa definiçãoRestTemplate:

@Bean
public RestTemplate getRestTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getInterceptors().add(new CompressingClientHttpRequestInterceptor());
    return restTemplate;
}

3. Tratamento de solicitações compactadas

Por padrão, a maioria dos servidores da Web não entende solicitações que contêm dados compactados. Os aplicativos da Web Spring não são diferentes. Portanto, precisamos configurá-los para lidar com essas solicitações.

Atualmente, apenas os servidores Web Jetty e Undertow tratam os corpos de solicitação com dados no formato GZIP. Consulte nosso artigo emSpring Boot Application Configuration para configurar um servidor web Jetty ou Undertow.

3.1. Jetty Web Server

Neste exemplo, personalizamos um servidor web Jetty adicionando um JettyGzipHandler. Este manipulador Jetty foi criado para compactar respostas e descomprimir solicitações.

No entanto, adicioná-lo ao servidor da web Jetty não é suficiente. Precisamos definir oinflateBufferSize para um valor maior que zero para permitir a descompressão:

@Bean
public JettyServletWebServerFactory jettyServletWebServerFactory() {
    JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
    factory.addServerCustomizers(server -> {
        GzipHandler gzipHandler = new GzipHandler();
        gzipHandler.setInflateBufferSize(1);
        gzipHandler.setHandler(server.getHandler());

        HandlerCollection handlerCollection = new HandlerCollection(gzipHandler);
        server.setHandler(handlerCollection);
    });
    return factory;
}

3.2. Undertow Web Server

Da mesma forma, podemos personalizar um servidor da web Undertow para descomprimir automaticamente solicitações para nós. Nesse caso, precisamos adicionar umRequestEncodingHandler personalizado.

Configuramos o manipulador de codificação para processar dados de origem GZIP a partir da solicitação:

@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
    UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
    factory.addDeploymentInfoCustomizers((deploymentInfo) -> {
        deploymentInfo.addInitialHandlerChainWrapper(handler -> new RequestEncodingHandler(handler)
          .addEncoding("gzip", GzipStreamSourceConduit.WRAPPER));
    });
    return factory;
}

4. Conclusão

E isso é tudo que precisamos fazer para que as solicitações compactadas funcionem!

Neste tutorial, cobrimos como criar um interceptor para umRestTemplate que compacta o conteúdo de uma solicitação. Além disso, vimos como descompactar automaticamente essas solicitações em nossos aplicativos da Web Spring.

É importante notar que devemosonly send compressed content to web servers capable of handling such requests.

Um exemplo funcional completo para o servidor da web Jetty está acima deon GitHub.