1. 개요

이 예제에서는 Spring RestTemplate  Interceptor 를 구현하는 방법을 배울 것 입니다.

응답에 사용자 지정 헤더를 추가하는 인터셉터를 만드는 예제를 살펴 보겠습니다.

2. 인터셉터 사용 시나리오

헤더 수정 외에도 RestTemplate 인터셉터가 유용한 기타 사용 사례 는 다음과 같습니다.

  • 요청 및 응답 로깅
  • 구성 가능한 백 오프 전략으로 요청 재시도
  • 특정 요청 매개 변수에 따른 요청 거부
  • 요청 URL 주소 변경

3. 인터셉터 생성

대부분의 프로그래밍 패러다임에서 인터셉터는 프로그래머가이를 인터셉트하여 실행을 제어 할 수 있도록하는 필수 부분입니다. Spring 프레임 워크는 다양한 목적으로 다양한 인터셉터를 지원합니다.

Spring RestTemplate을 사용하면 ClientHttpRequestInterceptor 인터페이스 를 구현하는 인터셉터를 추가 할 수  있습니다.  이 인터페이스 intercept (HttpRequest, byte [], ClientHttpRequestExecution) 메소드는 주어진 요청을 가로 채서 request , body실행 객체에 대한 액세스를 제공하여 응답을 반환 합니다.

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 () 메서드는 요청본문 을 인수로 포함 했기 때문에 요청을 수정하거나 특정 조건에 따라 요청 실행을 거부 할 수도 있습니다.

4. RestTemplate 설정

이제 인터셉터를 만들었으므로 RestTemplate 빈을 만들고 여기에 인터셉터를 추가해 보겠습니다 .

@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 객체에 이미 추가 된 인터셉터가있을 수 있습니다 . 따라서 모든 것이 예상대로 작동하는지 확인하기 위해 코드가 비어있는 경우에만 인터셉터 List을 초기화합니다.

코드에서 알 수 있듯이 기본 생성자를 사용하여 RestTemplate 개체 를 만들고 있지만 요청 / 응답 스트림을 두 번 읽어야하는 시나리오가 있습니다.

예를 들어, 인터셉터가 요청 / 응답 로거로 작동하도록하려면 인터셉터가 처음으로, 클라이언트가 두 번째로 두 번 읽어야합니다.

기본 구현에서는 응답 스트림을 한 번만 읽을 수 있습니다. 이러한 특정 시나리오를 충족시키기 위해 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<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
          );
        
        assertThat(
          responseEntity.getStatusCode(),
          is(equalTo(HttpStatus.OK))
        );
        assertThat(
          responseEntity.getHeaders().get("Foo").get(0),
          is(equalTo("bar"))
        );
    }
}

여기에서는 무료로 호스팅되는 HTTP 요청 및 응답 서비스  http://httpbin.org  를 사용하여 데이터를 게시했습니다. 이 테스트 서비스는 일부 메타 데이터와 함께 요청 본문을 반환합니다.

6. 결론

이 예제은 인터셉터를 설정하고이를 RestTemplate 객체에 추가하는 방법에 관한 것 입니다. 이러한 종류의 인터셉터는 들어오는 요청을 필터링, 모니터링 및 제어하는 ​​데 사용할 수도 있습니다.

RestTemplate 인터셉터 의 일반적인 사용 사례 는 헤더 수정입니다.이 기사에서 자세히 설명했습니다.

그리고 언제나처럼 Github 프로젝트 에서 예제 코드를 찾을 수 있습니다 . 이것은 Maven 기반 프로젝트이므로 그대로 가져 와서 실행하기 쉽습니다.