본문 바로가기
C#

[C#] HttpClient, IHttpClientFactory 차이와 올바른 사용법

by Minius 2024. 3. 25.
반응형

최근 인터페이스 사용이 잦아지며, 인터페이스가 아닌 코드를 인터페이스화 하는 작업을 하고 있다.

 

그러다 가끔 HttpClient와 IHttpClientFactory 처럼, 사용되는 변수와 들어가는 인스턴스의 형식이 다른걸 발견하게 된다.

 

궁금해서 왜 그런지 찾아보았는데, 결국 들어가는건 같은 형이 되었기 때문에 상관 없었지만, 조금 더 알아보았다.

 

그리고 차이를 찾았는데, 우리 회사에 있는 코드는 아래와 같다.

 

현재 사용중인 코드

public class MyService
{
    private readonly HttpClient _httpClient;

    public MyService(IHttpClientFactory httpClientFactory)
    {
        _httpClient = httpClientFactory.CreateClient();
    }

    public async Task<string> GetAsync(string url)
    {
        var response = await _httpClient.GetAsync(url);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsStringAsync();
    }
}

 

위와 같이 되면 _httpClient에 HttpClient 생성자를 저장하게 된다. 그러므로 HttpClient 생성자는 항상 살아있는 것이다.

하지만 이는 나중에 IHttpClientFactory가 나오게 된 이유에 반하게 된다.

 

.NET Core 2.1부터 IHttpClientFactory 인터페이스가 도입되었는데, HttpClient에 문제가 있기 때문이다.

HttpClient를 잘못 사용할 경우 리소스 낭비와 성능에 문제가 발생할 수 있는데, 이 인스턴스를 요청마다 생성하고 폐기하는 패턴에서 소켓 고갈 문제가 있을 수 있다고 한다. 왜냐하면 각 인스턴스가 폐기될 때마다 사용하던 소켓이 즉시 해제되지 않고, TIME_WAIT 상태로 남아있기 때문이다. 이러한 문제를 방지하기 위해 HttpClient를 재사용하는 것이 권장되지만, 이 경우에도 DNS 변경을 자동으로 감지하지 못하는 문제가 있을 수 있다.

 

그래서 IHttpClientFactory가 나오게 되었고, 인스턴스의 생성, 구성, 수명 관리를 담당하게 되었다. IHttpClientFactory가 위의 문제점을 효과적으로 해결할 수 있기 때문이다.

 

IHttpClientFactory의 장점

  1. HttpClient 인스턴스 관리: IHttpClientFactory는 내부적으로 HttpClient의 인스턴스 풀을 관리하여 필요할 때마다 인스턴스를 재사용함으로써 성능을 개선하고 소켓 고갈 문제를 방지할 수 있다.
  2. DNS 변경 감지: IHttpClientFactory를 사용하면 DNS 변경 사항을 자동으로 감지하고, 새 IP 주소로 요청을 보낼 수 있다. 이는 HttpClient를 장기간 재사용할 때 중요하다.
  3. 중앙 집중식 구성: IHttpClientFactory를 사용하면 모든 HttpClient 인스턴스에 대한 구성을 중앙에서 관리할 수 있다. 이를 통해 로깅, 인증 토큰 추가 등의 공통 로직을 쉽게 적용할 수 있다.
  4. 명시적 종속성 주입: IHttpClientFactory는 ASP.NET Core의 종속성 주입 시스템과 통합되어 HttpClient 인스턴스를 필요로 하는 클래스에 IHttpClientFactory 를 주입하여 사용할 수 있다.

따라서 위의 사용중인 코드가 아닌 아래의 코드처럼 작성하여야 IHttpClientFactory를 제대로 사용한다고 할 수 있겠다.

 

앞으로 지향해야 할 코드

private readonly IHttpClientFactory _httpClientFactory;

public MyService(IHttpClientFactory httpClientFactory)
{
    _httpClientFactory = httpClientFactory; // httpClientFactory 인스턴스를 저장
}

public async Task<HttpResponseMessage> GetAsync(string url)
{
    var httpClient = _httpClientFactory.CreateClient(); // 필요할 때마다 HttpClient 인스턴스를 생성
    return await httpClient.GetAsync(url);
}

 

각 메소드에서 필요할 때 마다 HttpClient 인스턴스를 생성하여 사용하는 것이다. 

댓글