1. 序章

この短いチュートリアルでは、圧縮データを含むHTTPリクエストを送信する方法を見ていきます。

さらに、圧縮されたリクエストを処理するようにSpringWebアプリケーションを構成する方法についても説明します。

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サーバーは圧縮データを含むリクエストを理解しません。 SpringWebアプリケーションも例外ではありません。 したがって、そのような要求を処理するように構成する必要があります。

現在、JettyおよびUndertow Webサーバーのみが、GZIP形式のデータを使用してリクエスト本文を処理します。 JettyまたはUndertowWebサーバーをセットアップするには、 Spring Boot ApplicationConfigurationに関する記事を参照してください。

3.1. JettyWebサーバー

この例では、Jetty GzipHandlerを追加してJettyWebサーバーをカスタマイズします。 このJettyハンドラーは、応答を圧縮し、要求を解凍するように構築されています。

ただし、JettyWebサーバーを追加するだけでは不十分です。 解凍を有効にするには、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. UndertowWebサーバー

同様に、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のインターセプターを作成する方法について説明しました。 また、SpringWebアプリケーションでこれらのリクエストを自動的に解凍する方法についても説明しました。

このようなリクエストを処理できるWebサーバーにのみ圧縮コンテンツを送信する必要があることに注意してください

Jetty Webサーバーの完全な実例は、GitHubにあります。