Java/Spring을 활용하여 외부 Http 서버에 요청을 보내고, REST 통신을 하기 위한 방법들을 정리한다. 오래된 기술 순으로 나열하면 다음과 같다.
- URLConnection
- HttpClient
- RestTemplate
- WebClient
실제 Spring 프로젝트를 만들어서 Http 요청/응답 처리를 해보며 각 라이브러리의 사용법 및 장단점 등을 공부해본다. 그 외 부수적으로 초보 개발자가 얻어갈 수 있는 내용들을 정리할 것이다.
project stack : java 17, spring boot 2.7.0, maven 4.0.0 / IDE : intellij Ultimate
1. URLConnection 소개
jdk 1.2부터 내장되었다. jdk 1.2는 1998년 Jave SE 1.2로 발표되었다. 다시 말해 꽤 오래되었다. 그러나 Http 통신 방식을 이해하는데는 도움이 된다.
2. 프로젝트 생성
intelliJ에서 제공하는 Spring Initalizr를 이용해서 프로젝트를 생성한다. java는 17버전, maven pjt, packaing은 jar로 했다.
dependency는 lombok과 spring web만 추가했다. 나머지는 필요하다면 직접 dependency를 추가하자.
3. 프로젝트 구조 생성
UrlConnection 뿐만 아니라 다른 것들도 공부할 것이기 때문에, 패키지를 분리해서 작성해두었다.
3-1. UrlConnectionConfig
URLConnection 객체와 관련된 환경설정 정보를 넣어준다. 설정 정보이기 때문에 @Configuration을 달아주고 @Bean으로 UrlConnection1 이라는 Bean을 생성하였다. 해당 객체를 참조하는 곳에서 URLConnection 객체를 받아서 쓸 수 있도록 return 해주었다.
@Configuration
public class UrlConnectionConfig {
@Bean
public URLConnection UrlConnection1() throws IOException {
//1. URL 객체 생성
URL url = new URL("https://www.naver.com");
//2. URL에서 URL Connection 객체 얻기
URLConnection urlCon = url.openConnection();
//3. 연결 정보 set
urlCon.setConnectTimeout(5000);
urlCon.setReadTimeout(10000);
return urlCon;
}
}
0. URLConnection은 IOException 및 하위 MalformedURLException, SocketTimeException, UnknownServiceException 등 HTTP 통신과 관련된 에러를 throws 해주도록 되어있다.
1. url 주소는 네이버로 지정했다. 만약 url을 동적으로 변경해주고 싶다면 UrlConnection1의 파라미터로 url을 지정하고 인자로 받아오면 될 것이다.
2. url.openConnection()을 통해서 연결을 해주어야한다.
3. 연결 정보를 지정해주었다. 가장 기본적으로 사용하는 ConnectionTimeout과 readTimeout만 지정해주었다. 연결이 5초 안에 안되면 에러, 읽어들이는 데이터가 10초 안에 안 읽어지면 에러를 반환한다는 것이다.
이외에도 URL에 연결하는데 필요한 기본적인 정보들을 설정해줄 수 있으며, 그 내용은 아래와 같다.(참조1)
메서드 이름 | 설명 |
setConnectTimeout(int timeout) | 연결 만료 시간을 설정한다. 연결되기 전에 timeout으로 지정한 시간이 지나면 SocketTimeoutException이 발생한다. 단위는 밀리초이며, 시간 초과가 0이면 무한대 timeout으로 기본값이 적용된다. |
setReadTimeout(int timeout) | 읽기 만료 시간을 설정한다. 지정 시간이 지나고 연결의 입력 스트림에서 읽을 수 있는 데이터가 없으면 SocketTimeoutException이 발생한다. 시간값이 0이면 무한대 timeout으로 기본값이 적용된다. |
setDefaultuseCaches(boolean default) | URLConnection의 캐시 사용 여부의 기본값을 정한다. URLConnection 클래스의 다음 인스턴스에 영향을 준다. Default = true |
setUseCaches(boolean useCaches) | 연결이 캐시를 사용하는지 여부를 설정한다. Default = true |
setDoInput(boolean doInput) | URLConnection을 서버에서 컨텐츠를 읽는데 사용할 수 있도록 설정한다. Default = true |
setDoOutput(boolean doOutput) | URLConnection이 서버에 데이터를 보내는데 사용할 수 있는지 여부를 설정한다. Default = false |
setIfModifiedSince(long time) | 주로 HTTP 프로토콜에 대해 클라이언트가 검색한 컨텐츠의 마지막 수정 시간을 새로 설정한다. 예를 들어, 서버가 지정된 시간 이후에 정적컨텐츠(이미지, HTML 등)가 변경되지 않았으면 컨텐츠를 가져오지 않고 상태 코드 304(수정되지 않음)를 반환한다. 클라이언트는 지정된 시간보다 최근에 수정된 경우 새로운 컨텐츠를 받게 된다. |
setAllowUserInteraction(Boolean allow) | 사용자 상호 작용을 활성화 또는 비활성화한다. 예를 들어 필요한 경우 인증 대화 상자를 표시한다. Default = false |
setDefaultAllowUserInteraction(Boolean default) | 이후의 모든 URLConnection 객체에 대한 사용자 상호 작용의 기본값을 설정한다. |
setRequestProperty(String key, String value) | Key, value 쌍으로 지정된 일반 요청 속성을 설정한다. 키가 있는 속성이 이미 있는 경우 이전 값을 새 값으로 적용한다. 연결 전에 호출되야하며, 일부 메서드는 이미 연결이 설정된 경우에는 IllegalStateException을 발생시킨다. |
setRequestMethod(String method) | HTTP 메서(GET, POST, HEAD, …)를 설정한다. Default = GET |
setChunkedStreamingMode(int chunkLength) | 컨텐츠의 길이를 미리 알 수 없는 경우 내부 버퍼링 없이 HTTP 요청 본문을 스트리밍할 수 있다. |
setFixedLengthStreamingMode(long contentLength) | 컨텐츠 길이를 미리 알고 있는 경우 내부 버퍼링 없이 HTTP 요청 본문을 스트리밍할 수 있다. |
setFollowRedirects(booealn follow) | HTTP 리다이렉션 뒤에 이 클래스의 미래 개체가 자동으로 따라야하는지 여부를 설정한다. Default = true |
setInstanceFoloowRedirects(booealn follow) | HTTP 리다이렉션 뒤에 HttpURLConnection 클래스의 인스턴스가 자동으로 따라와야 하는지 여부를 설정한다. Default = true |
3-2. UrlComponent1
위 환경설정 정보를 참조로하는 UrlComponent 클래스를 작성한다. 이 UrlComponent는 URLConnection 정보를 이용해서 어떤 기능을 정의하는 클래스이다. 여기서는 printPage라는 페이지 내용을 출력하는 간단한 메서드만 작성하였다.
@Component
@RequiredArgsConstructor
@Slf4j
public class UrlComponent1 {
private final URLConnection urlConnection1;
//페이지 출력하기
public void printPage() throws IOException {
Map<String, List<String>> headerFields = urlConnection1.getHeaderFields();
InputStream inputStream = urlConnection1.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream);
char[] chars = new char[4096];
reader.read(chars);
while((reader.read(chars) != -1)) {
String s = new String(chars);
log.info("s = {}", s);
}
}
}
1. 참조로 받아온 urlConnection1에서 getHeaderFields()를 해주었다. 응답의 header 값에 있는 정보들을 출력할 수 있다. 이외에도 getter 메서드들이 다양하다.
2. getInputStream()을 통해서 서버로 요청을 보냈을 때 응답 body 값을 얻어온다. 사용상의 편의를 위해서 InputStreamReader로 가져왔다.
-> 블로그 내 inputStream 참조글 : 자바 입력 : InputStream, InputStreamReader, BufferedStream, Scanner
3. 4096 비트의 크기를 갖는 char 배열을 지정하고, reader.read 메서드를 통해서 배열에 응답값이 담기도록 4096 비트씩 담기도록 했다. 만약 char[100]으로 정의한다면 100비트씩만 응답 정보가 담긴다.
4. reader.read(chars) != -1은 inputStream에 남은 정보가 없을 때까지 응답값을 읽어들인다는 의미이다.
5. new String(char[] chars)로 읽어온 char 배열 값을 String으로 변환할 수 있다. 그리고 log로 이 값들을 출력하게 하였다.
3-3. BasicController
마지막으로 웹 요청을 했을 때 UrlComponent1이 동작하도록 하기 위해서 Controller를 만들었다. 일반적으로 Controller 자체에서 어떤 기능을 하지는 않고, Service 단을 만들어서 그곳에서 기능을 처리하지만, 여기서는 해당 과정을 생략하고 그냥 Controller에서 처리했다.
@RestController
@RequiredArgsConstructor
public class BasicController {
private final UrlComponent1 urlComponent1;
@GetMapping(path = "/basic/url")
public String getUrlInfos() throws IOException {
urlComponent1.printPage();
return "ok";
}
}
3-4. 실행결과
서버를 띄우고 localhost:8080/basic/url로 요청을 보내면 log.info에 의해서 네이버에 접속했을 때 응답 body값들이 콘솔창에 출력되는 것을 확인할 수 있다.
참조
1. IT 이야기 - Java URL Connection과 HttpConnection 사용 방법
https://blueyikim.tistory.com/2199
'Programming-[Backend] > Spring' 카테고리의 다른 글
[TIL] spring WebFlux, WebClient - 비동기 polling (0) | 2024.11.19 |
---|---|
[TIL] Spring Java GC, OOM, JVM Heap dump - Memory Analyzer, pmd (0) | 2024.08.30 |
[TIL] 스프링 트랜잭션 따로 적용 하기 (REQUIRES_NEW), 클래스 분리 필요 (0) | 2022.05.21 |
[TIL]PageableDefault는 non-deterministic sort를 한다 (0) | 2022.04.04 |
[링크][탐험][작성중] WebMvcConfigurer, WebMvcConfigurationSupport, @EnableWebMvc (0) | 2022.03.03 |