Spring RestTemplateインターセプターの使用

Spring RestTemplateインターセプターの使用

1. 概要

このチュートリアルでは、Spring link:/ rest-template Interceptorを実装する方法を学習します。

応答にカスタムヘッダーを追加するインターセプターを作成する例を見ていきます。

2. インターセプターの使用シナリオ

ヘッダーの変更に加えて、RestTemplateインターセプターが役立つ他のユースケースのいくつかは次のとおりです。

  • 要求と応答のログ

  • 構成可能なバックオフ戦略で要求を再試行する

  • 特定のリクエストパラメータに基づくリクエスト拒否

  • リクエストURLアドレスの変更

3. インターセプターの作成

ほとんどのプログラミングパラダイムでは、interceptors are an essential part that enables programmers to control the execution by intercepting it. Springフレームワークは、さまざまな目的のためにさまざまなインターセプターもサポートしています。

SpringRestTemplateを使用すると、ClientHttpRequestInterceptorインターフェースを実装するインターセプターを追加できます。 このインターフェースのintercept(HttpRequest, byte[], ClientHttpRequestExecution)メソッドは、指定されたリクエストをインターセプトし、requestbodyexecutionオブジェクトへのアクセスを許可することでレスポンスを返します。

ClientHttpRequestExecution引数を使用して実際の実行を行い、リクエストを後続のプロセスチェーンに渡します。

最初のステップとして、ClientHttpRequestInterceptorインターフェースを実装するインターセプタークラスを作成しましょう。

public class RestTemplateHeaderModifierInterceptor
  implements ClientHttpRequestInterceptor {

    @Override
    public ClientHttpResponse intercept(
      HttpRequest request,
      byte[] body,
      ClientHttpRequestExecution execution) throws IOException {

        ClientHttpResponse response = execution.execute(request, body);
        response.getHeaders().add("Foo", "bar");
        return response;
    }
}

Our interceptor will be invoked for every incoming requestであり、実行が完了して戻ると、すべての応答にカスタムヘッダーFooが追加されます。

intercept()メソッドには引数としてrequestbodyが含まれているため、リクエストに変更を加えたり、特定の条件に基づいてリクエストの実行を拒否したりすることもできます。

4. RestTemplateの設定

インターセプターを作成したので、RestTemplate Beanを作成し、それにインターセプターを追加しましょう。

@Configuration
public class RestClientConfig {

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();

        List interceptors
          = restTemplate.getInterceptors();
        if (CollectionUtils.isEmpty(interceptors)) {
            interceptors = new ArrayList<>();
        }
        interceptors.add(new RestTemplateHeaderModifierInterceptor());
        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }
}

場合によっては、RestTemplateオブジェクトにインターセプターがすでに追加されている可能性があります。 したがって、すべてが期待どおりに機能することを確認するために、コードはインターセプターリストが空の場合にのみインターセプターリストを初期化します。

コードが示すように、デフォルトのコンストラクターを使用してRestTemplateオブジェクトを作成していますが、要求/応答ストリームを2回読み取る必要があるシナリオがいくつかあります。

たとえば、インターセプターを要求/応答ロガーとして機能させる場合は、インターセプターによる1回目とクライアントによる2回目の2回読み取る必要があります。

デフォルトの実装では、応答ストリームを1回だけ読み取ることができます。 このような特定のシナリオに対応するために、SpringはBufferingClientHttpRequestFactory.と呼ばれる特別なクラスを提供します。名前が示すように、このクラスは複数の使用のためにJVMメモリに要求/応答をバッファリングします。

BufferingClientHttpRequestFactoryを使用してRestTemplateオブジェクトを初期化し、リクエスト/レスポンスストリームのキャッシュを有効にする方法は次のとおりです。

RestTemplate restTemplate
  = new RestTemplate(
    new BufferingClientHttpRequestFactory(
      new SimpleClientHttpRequestFactory()
    )
  );

5. 例のテスト

RestTemplateインターセプターをテストするためのJUnitテストケースは次のとおりです。

public class RestTemplateItegrationTest {

    @Autowired
    RestTemplate restTemplate;

    @Test
    public void givenRestTemplate_whenRequested_thenLogAndModifyResponse() {
        LoginForm loginForm = new LoginForm("username", "password");
        HttpEntity requestEntity
          = new HttpEntity(loginForm);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        ResponseEntity responseEntity
          = restTemplate.postForEntity(
            "http://httpbin.org/post", requestEntity, String.class
          );

        assertThat(
          responseEntity.getStatusCode(),
          is(equalTo(HttpStatus.OK))
        );
        assertThat(
          responseEntity.getHeaders().get("Foo").get(0),
          is(equalTo("bar"))
        );
    }
}

ここでは、自由にホストされているHTTPリクエストおよびレスポンスサービスhttps://httpbin.org を使用してデータを投稿しました。 このテストサービスは、リクエストボディといくつかのメタデータを返します。

6. 結論

このチュートリアルでは、インターセプターを設定してRestTemplateオブジェクトに追加する方法について説明します。 この種のインターセプターは、着信要求のフィルタリング、監視、および制御にも使用できます。

RestTemplateインターセプターの一般的な使用例は、ヘッダーの変更です。これについては、この記事で詳しく説明しました。

そして、いつものように、サンプルコードはGithub projectにあります。 これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。