RestTemplate
RestTemplate이란?
RestTemplate restTemplate = new RestTemplate();
간편하게 Rest방식의 API를 호출할 수 있는 Spring 내장 클래스다.
Spring 3.0부터 지원이 되며, Json, Xml 응답을 모두 받을 수 있다.
HTTP 서버와의 통신 방법
Client와 Server로 나누어서 먼저 프로젝트를 생성한다.
참고로 Server는 Port번호를 8080으로, Client는 9090으로 설정했다.
아래 방법들은 모두 HTTP 메소드 중 GET을 기반으로 동작한다.
(1) Server의 ServerApiController
@RestController
@RequestMapping("/api/server")
public class ServerApiController {
@GetMapping("/hello")
public String hello(){
return "Hello Server!";
}
}
(2) Client의 ApiController
@RestController
@RequestMapping("/api/client")
public class ApiController {
//@Autowired가 다소 오래된 방법이라 직접 생성자를 만듦
private final RestTemplateService restTemplateService;
public ApiController(RestTemplateService restTemplateService) {
this.restTemplateService = restTemplateService;
}
@GetMapping("/hello")
public String getHello(){
return restTemplateService.hello();
}
}
(3) Client의 RestTemplateService
@Service
public class RestTemplateService {
public String hello(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/hello")
.encode()
.build()
.toUri();
System.out.println(uri.toString());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> result = restTemplate.getForEntity(uri, String.class); // 가져오겠다는 get이 아니라 HTTP의 GET을 의미함
System.out.println(result.getStatusCode());
System.out.println(result.getBody());
return result.getBody();
}
}
* UriComponentBuilder : 여러개의 파라미터를 이용하여 URL를 작성할 때에 개발자가 편하게 작성할 수 있도록 도와줌
* getForEntity : 가져오겠다는 get이 아니라 HTTP의 get method
위 코드의 실행 순서는 다음과 같다.
- localhost:8080/api/client/hello를 호출
- restTemplateService.hello()를 반환
- restTemplateService.hello()는 localhost:9090/api/server/hello를 호출하여 "Hello Server"를 리턴
번외 : URLConnection vs HttpClient
(1) URLConnection
Maven으로 RestTemplate을 이용하지 않고 순수하게 Java에서의 Class를 이용해서 HTTP 서버와 연결한다.
기본 JDK에 포함되며, HTTP뿐만 아니라 여러 프로토콜을 제공한다.
// http://www.test.co.kr/test.jsp에 있는 내용을 읽어올거다
URL obj = new URL("http://www.test.co.kr/test.jsp"); // 호출할 url
HttpURLConnection con = (HttpURLConnection)obj.openConnection();
con.setRequestMethod("GET");
in = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
String line;
while((line = in.readLine()) != null) { // response를 차례대로 출력
System.out.println(line);
}
위는 예시코드이며, URL의 내용을 읽어오거나 URL 주소에 GET,POST로 데이터를 전달할 때 사용한다.
단점으로 응답코드가 4XX이거나 5XX이면 IOException이 발생하며, 쿠키 제어가 불가능하다.
(2) HttpClient
org.apache.http.client에서 제공하는 라이브러리이다.
// http://localhost/api/server/hello에 요청해서
// response를 받을거다. 반환 타입은 Json이다.
public UserResponse hello(){
URI uri = UriComponentsBuilder
.fromUriString("http://localhost:9090")
.path("/api/server/hello")
.encode() // 안전하게 인코딩해서 보내자
.build()
.toUri();
System.out.println(uri.toString());
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<UserResponse> result = restTemplate.getForEntity(uri, UserResponse.class); // 주의. 여기서 get은 HTTP - GET을 뜻한다.
System.out.println(result.getStatusCode());
System.out.println(result.getBody());
return result.getBody();
}
아래에 기술될 내용처럼, URlConnection에 비해 장점이 많지만 단점도 존재한다.
UrlConnection을 이용한 방식보다 코드가 간결해졌지만 여전히 반복적이고 코드들이 길다.
또한 응답의 컨텐츠 타입에 따라 별도 로직이 필요하다.
UrlConnection과 HttpClient의 구체적인 차이점은 다음과 같다.
URL Connection | HTTPClient | |
Methods | HEAD, GET, POST, PUT, DELETE, TRACEAND OPTIONS 총합 7개만 존재 | 왼쪽의 7개 이외에 임의의 메소드들 존재 (ex : WEBDav, IPP) |
Response Codes | 응답코드 400미만의 body, headers 등을 읽음. 400이상의 응답코드는 IOExcepeiton 발생 |
상관없이 모두 읽어냄 |
Proxies and SOCKS | 모두 지원 (SOCKS : Version 4 only) | 모두 지원 (SOCKS : Version 4 and 5) |
Authorization | JDK 1.2 이상에서는 Basic 및 이전 버전의 Digest만 지원. 현재 버전의 Digest 인증(대부분 서버에서 지원하는 버전)은 지원되지 않으며, 버그로 인해 Apache에서 반환된 Digest 정보도 인식 불가 | Basic 및 Digest 인증 지원. 다른 스키마도 추가 가능 |
Cookies | NO | YES 그래서 세션을 유지할떄 HTTP Client를 사용 |
True request output streams | NO - 모든 데이터는 보내지기전에 완전히 버퍼링된다. | YES - HttpOutputStream이 직접적으로 소켓에 데이터를 송출한다. |
True Respons input stream | JDK 1.2이하 버젼에서는 YES. 1.3버젼부터는 NO. |
YES |
Persistent Connections | HTTP/1.0은 JDK1.2와 JDK1.2에서 Keep-alive JDK1.3은 HTTP/1.1의 지속성을 가짐. |
HTTP/1.0은 Keep-alive. HTTP/1.1은 지속성을 가짐. |
Pipelining of requests | No | Yes |
Can set timeouts | No | Yes |
Can handle protocols other than HTTP | Yes (ex : FTP, File, Malito) |
No |
Can do HTTP over SSL(https) | 적절한 Client를 제공하는 적절한 SSL 패키지를 설치해야함 | 다양한 무료 및 상용 SSL 패키지를 사용 가능 |
Source code available | No | Yes |
표에서 확인할 수 있듯이 HttpClient가 UrlConnection보다 장점이 많다.
RestTemplate 동작원리
- 어플리케이션이 RestTemplate를 생성하고, URI, HTTP 메소드 등의 헤더를 담아 요청한다.
- RestTemplate은 HttpMessageConverter을 사용하여 requsetEntity를 요청메세지로 변환한다.
- RestTemplate은 ClientHttpRequestFactory로 부터 ClientHttpRequest를 가져와서 요청을 보낸다.
- ClientHttpRequest는 요청 메세지를 만들어 HTTP 프로토콜을 통해 서버와 통신한다.
- RestTemplate은 RequestErrorHandler로 오류를 확인하고 있다면 처리로직을 태운다.
- ResponseErrorHandler는 오류가 있다면 ClientHttpResponse에서 응답데이터를 가져와서 처리한다.
- RestTemplate은 HttpMessageConverter를 이용해서 응답메세지를 Java Object (Class responseType)으로 변환한다.
- 어플리케이션이 반환된다.
RestTemplate 사용하기
HttpClient에 사용되느 주요 메소드는 다음과 같다.
Rest Template Method | HTTP Method | 설명 |
execute | Any | Request / Response 콜백을 수정 |
exchange | Any | HTTP 헤더를 새로 만들 수 있고 어떤 HTTP 메소드도 사용 가능 |
getForObject | GET | 주어진 URL주소로 get 요청을 보내고 객체로 결과를 반환 |
getForEntity | GET | 주어진 URL주소로 get 요청을 보내고 ResponseEntity로 결과를 반환 |
postForLocation | POST | post 요청을 보내고 헤더에 저장된 URI를 결과로 반환 |
postForObject | POST | post 요청을 보내고 객체로 결과를 반환 |
postForEntity | POST | post 요청을 보내고 결과를 ResponseEntity로 반환 |
put | PUT | 주어진 URL주소로 put 메소드 실행 |
delete | DELETE | 주어진 주소로 delete 메소드 실행 |
headForHeaders | HEAD | 헤더의 모든 정보를 얻을 수 있으므녀 head메소드를 사용 |
optionsForAllow | OPTIONS | 주어진 URL 주소에서 지원하는 HTTP메소드를 조회 |
참고 출처
떡건님 - httpclient와 urlconnection 차이점
빨간색소년님 - RestTemplate