C#

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

Minius 2024. 3. 25. 17:02
반응형

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

 

그러다 가끔 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 인스턴스를 생성하여 사용하는 것이다.