2.2. 자카르타 RESTful 웹 서비스 클라이언트

2.2.1. 자카르타 RESTful 웹 서비스 클라이언트 API

Jakarta RESTful Web Services 2.0은 HTTP 요청을 원격 RESTful 웹 서비스에 전송하기 위해 새 클라이언트 API를 도입했습니다. 3개의 주요 클래스가 있는 유연한 요청 빌드 API입니다.

  • 클라이언트
  • WebTarget
  • 응답

클라이언트 인터페이스는 WebTarget 인스턴스의 빌더입니다. WebTarget은 WebTarget 하위 리소스 WebTarget을 구축하거나 요청을 호출할 고유한 URL 또는 URL 템플릿을 나타냅니다.

클라이언트를 생성하는 방법에는 표준 방법 또는 ResteasyClientBuilder 클래스를 사용하는 두 가지 방법이 있습니다. ResteasyClientBuilder 클래스를 사용할 경우의 장점은 클라이언트를 구성하는 몇 가지 도우미 메서드를 제공한다는 것입니다.

ResteasyClientBuilder 클래스는 이러한 도우미 방법을 제공하지만 클래스는 JBoss EAP API에 따라 다릅니다. 애플리케이션을 새 서버로 마이그레이션하려면 애플리케이션을 다시 빌드해야 합니다. ResteasyClientBuilder 클래스는 RESTEasy에 따라 다르며 클래스는 이식할 수 없습니다.

클라이언트를 생성하는 표준 방법은 Jakarta RESTful Web Services 및 Jakarta EE API 사양을 모두 준수하며 Jakarta RESTful Web Services 구현에서 이식할 수 있습니다.

참고

Jakarta RESTful Web Services 애플리케이션이 이식성을 유지하도록 하려면 Jakarta EE API 사양을 준수하고 가능한 경우 Jakarta EE API 애플리케이션을 사용합니다. 사용 사례에서 Jakarta EE API 사용을 지원하지 않는 경우에만 JBoss 고유의 API를 사용합니다.

이러한 지침에 따라 애플리케이션을 다른 서버로 마이그레이션하거나 새로운 Jakarta EE 호환 JBoss 구현으로 마이그레이션할 때 발생할 수 있는 문제 수를 줄일 수 있습니다.

표준 방법을 사용하여 클라이언트 생성

다음 예제에서는 클라이언트를 생성하는 표준 방법 중 하나를 보여줍니다.

Client client = ClientBuilder.newClient();

또는 다른 표준 방법을 사용하여 아래 예와 같이 클라이언트를 생성할 수 있습니다.

Client client = ClientBuilder.newBuilder().build();
WebTarget target = client.target("http://foo.com/resource");
Response response = target.request().get();
String value = response.readEntity(String.class);
response.close();  // You should close connections!
ResteasyClientBuilder 클래스를 사용하여 클라이언트 생성

다음 예제에서는 ResteasyClientBuilder 클래스를 사용하여 클라이언트를 생성하는 방법을 보여줍니다.

ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://foo.com/resource");

Jakarta RESTful Web Services 2.1을 사용하면 ClientBuilder 클래스에 두 개의 시간 제한 메서드를 추가할 수 있습니다. 시간 제한 메서드는 사양 준수 메서드이며 RESTEasy 메서드를 사용하는 대신 사용할 수 있습니다.

다음 ClientBuilder 사양 준수 방법은 더 이상 사용되지 않는 특정 RESTEasy 메서드를 대체합니다.

  • connectTimeout 메서드는 establishConnectionTimeout 메서드를 대체합니다.

    connectTimeout 메서드는 새 서버 연결을 만들 때 클라이언트가 기다려야 하는 시간을 결정합니다.

  • readTimeout 메서드는 socketTimeout 메서드를 대체합니다.

    readTimeout 메서드는 클라이언트가 서버의 응답을 기다리는 시간을 결정합니다.

다음 예제에서는 connectTimeout 및 readTimeout 메서드에 대해 지정된 값을 보여줍니다.

import javx.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Client;

Client client = ClientBuilder.newBuilder()
	       .connectTimeout(100, TimeUnit.SECONDS)
	       .readTimeout(2, TimeUnit.SECONDS)
	       .build();

readTimeout 은 기존 연결에서 실행된 요청에 적용됩니다.

참고

timeout 매개 변수 값을 0으로 설정하면 서버가 무기한 대기합니다.

RESTEasy는 META-INF/services/javax.ws.rs.ext.Providers 파일에 나열된 모든 클래스를 포함하는 기본 프로바이더 세트를 자동으로 로드합니다. 또한 메서드 호출 Client.configuration() 에서 제공하는 구성 개체를 통해 다른 공급자, 필터 및 인터셉터를 수동으로 등록할 수 있습니다. 또한 구성을 사용하면 필요할 수 있는 구성 속성을 설정할 수 있습니다.

WebTarget 에는 상위 인스턴스에 등록된 구성 요소 및 속성을 상속하는 구성 인스턴스가 있습니다. 이를 통해 각 대상 리소스(예: 사용자 이름 및 암호)에 대한 특정 구성 옵션을 설정할 수 있습니다.

추가 리소스

  • ResteasyClientBuilder 클래스 및 해당 메서드에 대한 자세한 내용은 Class ResteasyClientBuilder 를 참조하십시오.
RESTEasy 클라이언트 클래스 사용

RESTEasy 클라이언트에 대한 다음 종속성을 Maven pom.xml 파일에 추가해야 합니다.

<dependency>
	<groupId>org.jboss.resteasy</groupId>
	<artifactId>resteasy-client</artifactId>
	<version>VERSION_IN_EAP</version>
 </dependency>

RESTEasy 클라이언트 클래스를 사용하는 작업 예제를 위해 JBoss EAP와 함께 제공되는 ja xrs-client 및 resteasy-jaxrs-client 빠른 시작을 참조하십시오.

클라이언트측 필터

클라이언트 쪽에는 두 가지 유형의 필터가 있습니다.

ClientRequestFilter
ClientRequestFilter 는 HTTP 요청을 서버로 전송하기 전에 실행됩니다. ClientRequestFilter 는 요청 실행을 중단하고 서버에 대한 유선을 사용하지 않고 준비된 응답을 제공할 수도 있습니다.
ClientResponseFilter
ClientResponseFilter 는 서버에서 응답을 수신한 후에 실행되지만 응답 본문이 마샬링되지 않습니다. ClientResponseFilter 는 애플리케이션 코드에 전달되기 전에 response 오브젝트를 수정할 수 있습니다. 다음 예제에서는 이러한 개념을 보여줍니다.
// execute request filters
for (ClientRequestFilter filter : requestFilters) {
	filter.filter(requestContext);
	if (isAborted(requestContext)) {
    return requestContext.getAbortedResponseObject();
  }
}

// send request over the wire
response = sendRequest(request);

// execute response filters
for (ClientResponseFilter filter : responseFilters) {
	filter.filter(requestContext, responseContext);
}
클라이언트측 필터를 클라이언트 요청에 등록

다음 예제에서는 클라이언트 측 필터를 클라이언트 요청에 등록하는 방법을 보여줍니다.

client = ClientBuilder.newClient();
WebTarget base = client.target(generateURL("/") + "get");
base.register(ClientExceptionsCustomClientResponseFilter.class).request("text/plain").get();
클라이언트 측 캐시

RESTEasy에는 클라이언트 측 캐시를 설정할 수 있는 기능이 있습니다. 이 캐시는 서버 응답으로 다시 전송된 cache-control 헤더를 찾습니다. cache-control 헤더가 클라이언트가 응답을 캐시할 수 있도록 지정하는 경우 RESTEasy는 로컬 메모리 내에 캐시합니다.

ResteasyWebTarget target = client.target(generateBaseUrl());
target.register(BrowserCacheFeature.class);
청크 인코딩 지원

RESTEasy는 클라이언트 API에 요청을 청크 전송 모드로 보내도록 지정하는 기능을 제공합니다. 아래와 같이 청크된 전송 모드를 지정하는 방법은 두 가지가 있습니다.

  • 청크된 모드로 모든 요청을 보내도록 org.jboss.resteasy.client.jaxrs.ResteasyWebTarget 을 구성할 수 있습니다.

    ResteasyClient client = new ResteasyClientBuilder().build();
    ResteasyWebTarget target = client.target("http://localhost:8081/test");
    target.setChunked(b.booleanValue());
    Invocation.Builder request = target.request();
  • 또는 청크된 모드로 보낼 특정 요청을 구성할 수도 있습니다.

    ResteasyClient client = new ResteasyClientBuilder().build();
    ResteasyWebTarget target = client.target("http://localhost:8081/test");
    ClientInvocationBuilder request = (ClientInvocationBuilder) target.request();
    request.setChunked(b);

    javax.ws.rs.client.Invocation.Builder 클래스와 달리 org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder 는 RESTEasy 클래스입니다.

참고

청크된 모드에서 요청을 보내는 기능은 기본 전송 계층에 따라 다릅니다. 특히, 사용 중인 org.jboss.resteasy.client.jaxrs.ClientHttpEngine 클래스의 구현에 따라 달라집니다. 현재는 기본 구현 ApacheHttpClient43Engine 과 이전 구현 ApacheHttpClient4Engine 만 청크된 모드를 지원합니다. 이 두 가지는 모두 org.jboss.resteasy.client.jaxrs.engines 패키지에서 사용할 수 있습니다. 자세한 내용은 HTTP 클라이언트로 RESTEasy 구현 섹션을 참조하십시오.

2.2.2. HTTP 클라이언트로 RESTEasy 구현

클라이언트와 서버 간의 네트워크 통신은 기본적으로 RESTEasy에서 처리됩니다. Apache HttpComponents 프로젝트의 HttpClient 를 사용합니다. RESTEasy 클라이언트 프레임워크와 네트워크 간의 인터페이스는 ClientHttpEngine 인터페이스에서 정의합니다.

RESTEasy는 이 인터페이스의 네 가지 구현과 함께 제공됩니다. 기본 구현은 ApacheHttpClient43Engine 입니다. 이 구현에서는 Apache 4.3을 사용합니다.

ApacheHttpClient4Engine 은 Apache 4.3 이전 버전을 사용하는 구현입니다. 이 클래스는 이전 버전과의 호환성을 제공합니다. RESTEasy는 Apache 버전의 탐지를 기반으로 이 두 개의 ClientHttpEngine 구현 중 하나를 자동으로 선택합니다. InMemoryClientEngine 은 동일한 JVM의 서버로 요청을 디스패치하는 구현이며 URLConnectionEnginejava.net.HttpURLConnection 을 사용하는 구현입니다.

클라이언트 실행자는 특정 ClientRequest 로 전달할 수 있습니다.

ResteasyClient client = new
ResteasyClientBuilder().httpEngine(engine).build();

RESTEasy 및 HttpClient 는 HttpClient를 참조하지 않고 클라이언트 프레임워크를 사용하도록 기본 결정을 내립니다 . 그러나 일부 애플리케이션의 경우 HttpClient 세부 정보를 자세히 살펴보아야 할 수 있습니다. ApacheHttpClient43EngineApacheHttpClient4Engineorg.apache.http.client.HttpClient 및 org. apache.http.protocol.HttpContext 의 인스턴스를 제공하여 HttpClient 계층에 추가 구성 세부 정보를 전달할 수 있습니다. 예를 들어 인증을 다음과 같이 구성할 수 있습니다.

// Configure HttpClient to authenticate preemptively
// by prepopulating the authentication data cache.

// 1. Create AuthCache instance
AuthCache authCache = new BasicAuthCache();

// 2. Generate BASIC scheme object and add it to the local auth cache
AuthScheme basicAuth = new BasicScheme();
authCache.put(new HttpHost("sippycups.bluemonkeydiamond.com"), basicAuth);

// 3. Add AuthCache to the execution context
BasicHttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

// 4. Create client executor and proxy
HttpClient httpClient = HttpClientBuilder.create().build();
ApacheHttpClient4Engine engine = new ApacheHttpClient4Engine(httpClient, localContext);
ResteasyClient client = new ResteasyClientBuilder().httpEngine(engine).build();

HttpContextProvider 는 RESTEasy에서 제공하는 인터페이스로, ApacheHttpClient43Engine 및 ApacheHttpClient4Engine 구현에 사용자 지정 HttpContext 를 제공할 수 있습니다.

참고

연결 해제 와 연결 종료 의 차이점을 이해하는 것이 중요합니다. 연결을 해제하면 재사용할 수 있습니다. 연결을 종료하면 리소스를 확보하고 사용할 수 없게 됩니다.

RESTEasy는 알림 없이 연결을 해제합니다. 유일한 카운터 예제는 응답이 InputStream 의 인스턴스인 경우이며 명시적으로 닫혀야 합니다.

반면 호출 결과가 Response의 인스턴스인 경우 Response .close() 메서드를 사용하여 연결을 해제해야 합니다.

WebTarget target = client.target("http://localhost:8081/customer/123");
Response response = target.request().get();
System.out.println(response.getStatus());
response.close();

이 작업은 최종 블록에서 실행할 수 있습니다 . 연결을 해제하면 다른 용도로 사용할 수 있습니다. 일반적으로 소켓을 닫지 않습니다.

ApacheHttpClient4Engine.finalize() 는 열려 있는 모든 소켓을 닫습니다. JDK를 사용하여 finalize() 를 호출하는 것은 안전하지 않습니다. HttpClientApacheHttpClient4Executor 에 전달되면 아래와 같이 사용자가 연결을 종료해야 합니다.

HttpClient httpClient = new HttpClientBuilder.create().build();
ApacheHttpClient4Engine executor = new ApacheHttpClient4Engine(httpClient);
...
httpClient.getConnectionManager().shutdown();
참고

ApacheHttpClient4EngineHttpClient 의 자체 인스턴스를 생성한 경우, 오픈 소켓을 닫기 위해 finalize() 를 기다릴 필요가 없습니다. ClientHttpEngine 인터페이스에는 이러한 목적을 위한 close() 메서드가 있습니다.

마지막으로 javax.ws.rs.client.Client 클래스에서 자동으로 엔진을 생성한 경우 Client.close() 를 호출합니다. 이 호출은 모든 소켓 연결을 정리합니다.

2.2.2.1. HTTP 리디렉션

Apache HttpClient를 기반으로 하는 ClientHttpEngine 구현은 HTTP 리디렉션을 지원합니다. 이 fCenterre는 기본적으로 비활성화되어 있습니다. 다음과 같이 setFollowRedirects 메서드를 true 로 설정하여 활성화할 수 있습니다.

ApacheHttpClient43Engine engine = new ApacheHttpClient43Engine();
engine.setFollowRedirects(true);
Client client = new ResteasyClientBuilder().httpEngine(engine).build();