1. 概要

このチュートリアルでは、Spring RestTemplate Interceptorを実装する方法を学習します。

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

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

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

  • リクエストとレスポンスのログ
  • 構成可能なバックオフ戦略を使用してリクエストを再試行する
  • 特定のリクエストパラメータに基づくリクエスト拒否
  • リクエストURLアドレスの変更

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

ほとんどのプログラミングパラダイムでは、インターセプターは、プログラマーがインターセプトすることで実行を制御できるようにするための重要な部分です。 Springフレームワークは、さまざまな目的のさまざまなインターセプターもサポートしています。

Spring RestTemplate を使用すると、ClientHttpRequestInterceptorインターフェイスを実装するインターセプターを追加できます。 このインターフェースのintercept(HttpRequest、byte []、ClientHttpRequestExecution)メソッドは、指定されたリクエストをインターセプトし、 request body およびexecutionオブジェクト。

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;
    }
}

インターセプターはすべての着信要求に対して呼び出され、実行が完了して戻ると、すべての応答にカスタムヘッダーFooを追加します。

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

4. RestTemplateの設定

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

@Configuration
public class RestClientConfig {

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

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

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

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

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

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

RestTemplateオブジェクトがBufferingClientHttpRequestFactoryを使用して初期化され、要求/応答ストリームのキャッシュが有効になる方法は次のとおりです。

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<LoginForm> requestEntity
          = new HttpEntity<LoginForm>(loginForm);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        
        ResponseEntity<String> responseEntity
          = restTemplate.postForEntity(
            "http://httpbin.org/post", requestEntity, String.class
          );
        
        Assertions.assertEquals(responseEntity.getStatusCode(), HttpStatus.OK);
        Assertions.assertEquals(responseEntity.getHeaders()
                .get("Foo")
                .get(0), "bar");
    }
}

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

6. 結論

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

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

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