[Spring] HTTP 다양한 통신 방법(URLConnection, HttpClient, RestTemplate, WebClient)

devdo·2024년 4월 21일
0

SpringBoot

목록 보기
41/42
post-thumbnail

URLConnection

설명

jdk 1.2부터 내장되어 있으며 java.net 패키지에 있다. URL의 내용을 읽어오거나 URL 주소에 대해 HTTP 통신 및 GET, POST로 데이터를 전달할 때 사용한다.

URLConnection 클래스를 사용하는 방법은 아래와 같다.

  1. URL 객체 생성
  2. 생성된 URL 객체의 openConnection() 메서드를 통해 URLConnection 획득
  3. 리턴된 URLConnection 객체 설정
  4. 헤더 필드 읽기
  5. 입력 스트림으로 데이터 읽기
  6. 출력 스트림으로 데이터 쓰기
  7. 연결 종료

코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class URLConnectionExample {
    public static void main(String[] args) throws IOException {
        URL url = new URL("https://httpbin.org/get");
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();

        try {
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5000); // 연결 타임아웃 설정 (5초)
            connection.setReadTimeout(5000);    // 읽기 타임아웃 설정 (5초)

            int responseCode = connection.getResponseCode();
            System.out.println("Response Code: " + responseCode);

            if (responseCode >= 200 && responseCode < 300) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
                    String line;
                    StringBuilder response = new StringBuilder();
                    while ((line = reader.readLine()) != null) {
                        response.append(line);
                    }
                    System.out.println("Response Body: " + response.toString());
                }
            } else {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getErrorStream()))) {
                    String line;
                    StringBuilder errorResponse = new StringBuilder();
                    while ((line = reader.readLine()) != null) {
                        errorResponse.append(line);
                    }
                    System.err.println("Error Response Body: " + errorResponse.toString());
                }
            }

        } finally {
            connection.disconnect();
        }
    }
}

💥 문제점

  • 응답코드가 4xx 이거나 5xx 일 경우 IOException 이 터진다.
  • 타임아웃을 설정할 수 없다.
  • 쿠키 제어가 불가능하다.

HttpClient

설명

HTTP 프로토콜을 손쉽게 사용할 수 있도록 도와주는 Apache HTTP 컴포넌트이다.

  1. HttpClient httpClient = new DefaultHttpClient(); 처럼 HttpClient 객체 생성

  2. 메소드에 따라 new HttpGet("http://..." URL 정보)

  3. 응답받기 위한 객체 생성

    HttpResponse response = httpClient.execute(httpGet);

  4. HttpEntity entity = response.getEntity();

  5. Steam 처리

코드

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

public class HttpClientExample {
    public static void main(String[] args) throws IOException {
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet("https://httpbin.org/get");

        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(5000)
                .setSocketTimeout(5000)
                .build();
        httpGet.setConfig(requestConfig);

        HttpResponse response = httpClient.execute(httpGet);
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            String responseBody = EntityUtils.toString(entity);
            System.out.println("Response: " + responseBody);
            EntityUtils.consume(entity); // 스트림 비우기
        }
    }
}

URLConnetion 과의 차이점

  • 모든 응답코드를 읽을수 있다.
  • 타임아웃 설정 가능하다.
  • 쿠키 제어가 가능하다.

문제점

  • URLConnection을 사용하는 방식보다 코드가 간결해졌으나, 여전히 반복적이고 코드가 길다.
  • 스트림 처리 로직을 별도로 짜야한다.
  • 응답의 컨텐츠타입에 따라 별도 로직이 필요하다.

RestTemplate

스프링에서 제공하는 http통신에 유용하게 쓸 수 있는 템플릿이며, HTTP 서버와의 통신을 단순화하고 RESTful 원칙을지킨다. RestTemplate는 기계적이고 반복적인 코드들을 깔끔하게 정리해준다.

☑️ 장점

  • 기계적이고 반복적인 코드를 최대한 줄여준다. URL, Response 받을 Object 설정 등
  • RESTful 형식에 맞춘다.
  • 멀티쓰레드 방식을 사용한다.
  • Blocking 방식을 사용한다.
  • json, xml을 쉽게 응답받는다

어플리케이션이 RestTemplate를 생성하고, URI, HTTP 메소드 등의 헤더를 담아 요청한다.
RestTemplate 는 HttpMessageConverter 를 사용하여 requestEntity 를 요청메세지로 변환한다.
RestTemplate 는 ClientHttpRequestFactory 로 부터 ClientHttpRequest 를 가져와서 요청을 보낸다.

ClientHttpRequest 는 요청메세지를 만들어 HTTP 프로토콜을 통해 서버와 통신한다.
RestTemplate 는 ResponseErrorHandler 로 오류를 확인하고 있다면 처리로직을 태운다.

ResponseErrorHandler 는 오류가 있다면 ClientHttpResponse 에서 응답데이터를 가져와서 처리한다.

RestTemplate 는 HttpMessageConverter 를 이용해서 응답메세지를 JSON으로 변환하여 어플리케이션에 반환되기에 아주 좋다.

코드

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class RestTemplateExample implements CommandLineRunner {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
                .setConnectTimeout(java.time.Duration.ofMillis(5000))
                .setReadTimeout(java.time.Duration.ofMillis(5000))
                .build();
    }

    public static void main(String[] args) {
        SpringApplication.run(RestTemplateExample.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        RestTemplate restTemplate = restTemplate(new RestTemplateBuilder());
        String response = restTemplate.getForObject("https://httpbin.org/get", String.class);
        System.out.println("Response: " + response);
    }
}

WebClient

스프링 5.0에서 추가된 인터페이스다. 스프링 5.0 이전에는 비동기 클라이언트로 AsyncRestTemplate를 사용했었다.

하지만 스프링 5.0 이후부터는 WebClient를 사용할 것을 권장한다.

☑️ 특징

  • 싱글 스레드 방식을 사용한다.
  • Non-Blocking 방식을 사용한다.
  • JSON, XML을 쉽게 응답받는다.

코드

☑️ 사용하기 위해선 webflux 의존성을 추가해줘야 한다.

implementation 'org.springframework.boot:spring-boot-starter-webflux'
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

@SpringBootApplication
public class WebClientExample implements CommandLineRunner {

    @Bean
    public WebClient webClient(WebClient.Builder builder) {
        return builder
                .baseUrl("https://httpbin.org")
                .build();
    }

    public static void main(String[] args) {
        SpringApplication.run(WebClientExample.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        WebClient client = webClient(WebClient.builder());
        Mono<String> result = client.get()
                .uri("/get")
                .retrieve()
                .bodyToMono(String.class);

        result.subscribe(response -> System.out.println("Response: " + response));
        // 비동기 작업이므로 결과를 기다리기 위해 잠시 대기 (실제 애플리케이션에서는 더 적절한 방법 사용)
        Thread.sleep(2000);
    }
}

RestTemplate와 WebClient의 차이

RestTemplate와 WebClient의 가장 큰 차이점은 Non-Blocking과 비동기화 가능 여부이다.

이러한 이유때문에 스프링에서는 WebClient 사용을 권장하는 이유다.

RestTemplate WebClient
Non-Blocking 불가능 가능
비동기화 불가능 가능

blocking

블로킹은 말 그대로 하나의 작업이 진행중일 때 끝날때까지 작업이 중단된다는 의미이다.

하나의 작업이 진행되고 완료될 때까지 모든 일을 중단한 상태로 대기해야 하는 것을 블로킹 방식이라고 한다.

블로킹 방식의 소켓통신은 결과가 올 때까지 다른 작업을 중단하고 하염없이 대기중이게 된다.

Non-blocking

Bloking과 반대로 하나의 작업이 진행중일 때 끝날때까지 작업이 중단되지 않고 다른 작업을 진행한다는 의미이다.

하나의 작업을 진행하면서 다른 작업도 진행할 수 있으므로 효율이나 반응속도가 더 뛰어나다.

하지만 설계가 복잡해진다는 단점이 있습니다.


알려주신 내용에 대한 수정 사항과 비교표, 그리고 보충 코드 예시를 아래와 같이 Markdown 형식으로 제공합니다.

비교표

기능URLConnectionHttpClient (Apache)RestTemplate (Spring)WebClient (Spring WebFlux)
블로킹 여부블로킹블로킹블로킹논블로킹
비동기 지원제한적제한적불가능가능 (Reactive)
에러 처리4xx, 5xx 응답 시 IOException 발생 (기본)모든 응답 코드 접근 가능편리한 에러 핸들링 메커니즘 제공 (ResponseErrorHandler)Reactive Streams 기반 에러 처리
타임아웃 설정가능 (setConnectTimeout(), setReadTimeout())가능 (RequestConfig 설정)가능 (RestTemplateBuilder 또는 ClientHttpRequestFactory 설정)가능 (java.time.Duration 설정)
쿠키 관리가능 (CookieHandler, CookieManager)가능 (CookieStore, CookieSpec)가능 (자동 쿠키 관리)가능 (자동 쿠키 관리)
응답 데이터 변환스트림 처리 필요스트림 처리 및 컨텐츠 타입별 처리 필요JSON, XML 자동 변환 (HttpMessageConverter 활용)JSON, XML 자동 변환 (Codec 지원)
외부 의존성없음 (JDK 내장)Apache HttpClientSpring FrameworkSpring WebFlux
간결성상대적으로 복잡URLConnection보다 간결하지만 RestTemplate보다 복잡매우 간결간결하고 함수형 스타일
사용 시점간단한 HTTP 통신, JDK만 필요한 경우복잡한 HTTP 통신 설정, 세밀한 제어 필요 시Spring 기반 애플리케이션에서 RESTful API 호출 시Spring WebFlux 기반 비동기/반응형 애플리케이션에서 RESTful API 호출 시

출처

profile
배운 것을 기록합니다.

0개의 댓글

관련 채용 정보