HttpClient 메시지 처리기

등록일시: 2013-09-04 17:16,  수정일시: 2013-09-18 22:55
조회수: 7,031
이 문서는 ASP.NET Web API 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

메시지 처리기(Message Handler)는 HTTP 요청을 받아서 HTTP 응답을 반환하는 클래스입니다.

일반적으로 일련된 메시지 처리기들은 서로 연결되어 물려 있습니다. 첫 번째 처리기가 HTTP 요청을 받아서 특정 처리를 수행한 다음, 다시 요청을 다음 처리기로 넘겨줍니다. 이런 상황이 반복되다가 특정 시점에 응답이 생성되고, 이번에는 다시 반대로 연결을 거슬러 되돌아가게 됩니다. 이런 패턴을 위임(Delegating) 처리기라고 부릅니다.

클라이언트 측에서 HttpClient 클래스는 요청 처리를 위해서 메시지 처리기를 사용합니다. 기본 처리기는 네트워크 너머로 요청을 전송하고 서버로부터 응답을 받는 HttpClientHandler 입니다. 물론, 클라이언트 파이프라인에 사용자 정의 메시지 처리기를 추가할 수도 있습니다:

노트: 서버 측에서 ASP.NET Web API도 메시지 처리기를 사용합니다. 더 자세한 정보는 HTTP Message Handlers를 참고하시기 바랍니다.

사용자 정의 메시지 처리기

사용자 정의 메시지 처리기를 작성하려면, System.Net.Http.DelegatingHandler 클래스를 상속 받아서 SendAsync 메서드를 재작성해야 합니다. 다음은 메서드 시그니쳐입니다:

Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken);

이 메서드는 HttpRequestMessage를 입력받아서 비동기적으로 HttpResponseMessage를 반환합니다. 일반적인 구현은 다음과 같습니다:

  1. 요청 메시지를 처리합니다.
  2. base.SendAsync를 호출해서 요청을 내부 처리기로 전달합니다.
  3. 내부 처리기가 응답 메시지를 반환합니다. (이 과정은 비동기적으로 처리됩니다.)
  4. 응답을 처리한 다음, 이를 호출자에게 반환합니다.

다음 예제는 외부로 나가는 요청에 사용자 정의 헤더를 추가하는 메시지 처리기를 보여줍니다:

class MessageHandler1 : DelegatingHandler
{
    private int _count = 0;
    
    protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        _count++;
        request.Headers.Add("X-Custom-Header", _count.ToString());
        return base.SendAsync(request, cancellationToken);
    }
}

이 예제에서 base.SendAsync 호출은 비동기적으로 처리됩니다. 만약, 이 호출 이후에 처리기가 수행하는 작업이 존재한다면, await 키워드를 사용해서 이 메서드 호출이 완료된 이후에 실행을 계속하십시요. 가령, 다음 예제는 오류 코드 로그를 남기는 처리기를 보여주고 있습니다. 로그를 남기는 작업 자체는 그다지 흥미로운 부분이 없지만, 이 예제를 통해서 처리기 내부에서 응답의 정보들을 가져오는 방법을 살펴볼 수 있습니다.

class LoggingHandler : DelegatingHandler
{
    StreamWriter _writer;
    
    public LoggingHandler(Stream stream)
    {
        _writer = new StreamWriter(stream);
    }
    
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var response = await base.SendAsync(request, cancellationToken);
    
        if (!response.IsSuccessStatusCode)
        {
            _writer.WriteLine("{0}\t{1}\t{2}", request.RequestUri,
                (int)response.StatusCode, response.Headers.Date);
        }
        return response;
    }
    
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            _writer.Dispose();
        }
        base.Dispose(disposing);
    }
}

클라이언트 파이프라인에 메시지 처리기 추가하기

사용자 정의 처리기를 HttpClient에 추가하려면, HttpClientFactory.Create 메서드를 사용합니다:

HttpClient client = HttpClientFactory.Create(new Handler1(), new Handler2(), new Handler3());

메시지 처리기들은 Create 메서드에 전달된 순서 그대로 호출됩니다. 처리기들은 중첩되어 있기 때문에, 응답 메시지는 반대 방향으로 이동합니다. 즉, 가장 마지막 처리기가 가장 첫 번째로 응답 메시지를 받습니다.