Spring RestTemplateを使用してリクエストを圧縮する方法

1. 前書き

この短いチュートリアルでは、圧縮データを含むHTTPリクエストを送信する方法について説明します。
さらに、圧縮された要求を処理するようにSpring Webアプリケーションを構成する方法についても説明します。

2. 圧縮されたリクエストの送信

まず、バイト配列を圧縮するメソッドを作成しましょう。 これはまもなく便利になります:
public static byte[] compress(byte[] body) throws IOException {
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(baos)) {
        gzipOutputStream.write(body);
    }
    return baos.toByteArray();
}
次に、_ClientHttpRequestInterceptor_を実装してリクエストを変更する必要があります。 適切なHTTP圧縮ヘッダーを送信するとともに、body-compressingメソッドを呼び出すことに注意してください。
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));
}
インターセプターは、アウトバウンドリクエスト本文を取得し、GZIP形式を使用して圧縮します。 この例では、Javaの標準_GZIPOutputStream_を使用して作業を行っています。
さらに、データエンコーディングに適切なヘッダーを追加する必要があります。 これにより、宛先エンドポイントは、GZIPで圧縮されたデータを処理していることを認識できます。
最後に、インターセプターを_RestTemplate_定義に追加します。
@Bean
public RestTemplate getRestTemplate() {
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getInterceptors().add(new CompressingClientHttpRequestInterceptor());
    return restTemplate;
}

3. 圧縮されたリクエストの処理

デフォルトでは、ほとんどのWebサーバーは圧縮データを含むリクエストを理解しません。 Spring Webアプリケーションも同様です。 したがって、このような要求を処理するように構成する必要があります。
現在、JettyおよびUndertow Webサーバーのみが、GZIP形式のデータを持つリクエスト本文を処理します。 JettyまたはUndertow Webサーバーをセットアップするには、https://www.baeldung.com/spring-boot-application-configuration [Spring Boot Application Configuration]の記事を参照してください。

3.1. Jetty Webサーバー

この例では、Jetty _GzipHandler_を追加してJetty Webサーバーをカスタマイズします。 このJettyハンドラーは、応答を圧縮し、要求を圧縮解除するために構築されています。
ただし、Jetty Webサーバーに追加するだけでは十分ではありません。 _inflateBufferSize_をゼロより大きい値に設定して、圧縮解除を有効にする必要があります。
@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サーバー

同様に、Undertow Webサーバーをカスタマイズして、リクエストを自動的に解凍できます。 この場合、カスタム_RequestEncodingHandler_を追加する必要があります。
要求からのGZIPソースデータを処理するようにエンコーディングハンドラーを構成します。
@Bean
public UndertowServletWebServerFactory undertowServletWebServerFactory() {
    UndertowServletWebServerFactory factory = new UndertowServletWebServerFactory();
    factory.addDeploymentInfoCustomizers((deploymentInfo) -> {
        deploymentInfo.addInitialHandlerChainWrapper(handler -> new RequestEncodingHandler(handler)
          .addEncoding("gzip", GzipStreamSourceConduit.WRAPPER));
    });
    return factory;
}

4. 結論

圧縮されたリクエストを機能させるために必要なことはこれだけです!
このチュートリアルでは、リクエストのコンテンツを圧縮する_RestTemplate_のインターセプターを作成する方法を説明しました。 また、Spring Webアプリケーションでこれらのリクエストを自動的に解凍する方法を検討しました。
*このようなリクエストを処理できるWebサーバーにのみ圧縮コンテンツを送信する必要があることに注意することが重要です。
Jetty Webサーバーの完全な実例は、https://github.com/eugenp/tutorials/tree/master/spring-rest-compress [on GitHub]にあります。