ensureSuccessStatusCode 사용 및 발생하는 HttpRequestException 처리


104

의 사용 패턴은 HttpResponseMessage.EnsureSuccessStatusCode()무엇입니까? 그것은 메시지의 내용을 폐기하고 던진다 HttpRequestException. 그러나 나는 그것을 제네릭과 다르게 프로그래밍 방식으로 처리하는 방법을 보지 못한다 Exception. 예를 들어, 그것은 HttpStatusCode편리했을 것입니다.

더 많은 정보를 얻을 수있는 방법이 있습니까? 누구든지 EnsureSuccessStatusCode()HttpRequestException과 관련된 사용 패턴을 보여줄 수 있습니까?

답변:


156

의 관용적 사용법은 EnsureSuccessStatusCode특정 방식으로 실패 사례를 처리하고 싶지 않을 때 요청의 성공을 간결하게 확인하는 것입니다. 이것은 클라이언트의 프로토 타입을 빠르게 만들고 싶을 때 특히 유용합니다.

특정 방식으로 실패 사례를 처리하기로 결정한 경우 다음을 수행하지 마십시오.

var response = await client.GetAsync(...);
try
{
    response.EnsureSuccessStatusCode();
    // Handle success
}
catch (HttpRequestException)
{
    // Handle failure
}

이것은 즉시 그것을 잡기 위해 예외를 던집니다. 이 목적을 위해 의 IsSuccessStatusCode속성 HttpResponseMessage이 있습니다. 대신 다음을 수행하십시오.

var response = await client.GetAsync(...);
if (response.IsSuccessStatusCode)
{
    // Handle success
}
else
{
    // Handle failure
}

1
실제 정수 상태 코드 를 얻는 방법이 있습니까? 이것을 시도하면 404 상태 코드 대신 "NotFound"와 같은 문자열이 나타납니다.
NickG

12
@NickG (int)response.StatusCode(참조 msdn.microsoft.com/en-us/library/...를 )
디모데 방패

1
VerifySuccessStatusCode ()에 의해 throw되는 기본 HttpRequestException에는 이유 구문이 있습니다. 그러나 성공하지 못한 경우 응답에서 어쨌든 해당 속성에 액세스 할 수 있습니다.
Stefan Zvonar

@StefanZvonar 귀하가 작성한 예외에서 이유 구문을 찾을 수 없습니다.
KansaiRobot

1
@NickG HTTP 상태 코드의 숫자 값을 얻기 위해 (int) response.StatusCode를 사용할 수 있습니다.
Henrik Holmgaard Høyer

95

나는 의미있는 것을 반환하지 않기 때문에 ensureSuccessStatusCode를 좋아하지 않습니다. 그래서 내 자신의 확장 프로그램을 만들었습니다.

public static class HttpResponseMessageExtensions
{
    public static async Task EnsureSuccessStatusCodeAsync(this HttpResponseMessage response)
    {
        if (response.IsSuccessStatusCode)
        {
            return;
        }

        var content = await response.Content.ReadAsStringAsync();

        if (response.Content != null)
            response.Content.Dispose();

        throw new SimpleHttpResponseException(response.StatusCode, content);
    }
}

public class SimpleHttpResponseException : Exception
{
    public HttpStatusCode StatusCode { get; private set; }

    public SimpleHttpResponseException(HttpStatusCode statusCode, string content) : base(content)
    {
        StatusCode = statusCode;
    }
}

Microsoft의 ensureSuccessStatusCode에 대한 소스 코드는 여기 에서 찾을 수 있습니다.

SO 링크를 기반으로 한 동기 버전 :

public static void EnsureSuccessStatusCode(this HttpResponseMessage response)
{
    if (response.IsSuccessStatusCode)
    {
        return;
    }

    var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

    if (response.Content != null)
        response.Content.Dispose();

    throw new SimpleHttpResponseException(response.StatusCode, content);
}

IsSuccessStatusCode에 대해 내가 싫어하는 점은 "멋지게"재사용 할 수 없다는 것입니다. 예를 들어 polly 와 같은 라이브러리를 사용 하여 네트워크 문제가 발생한 경우 요청을 반복 할 수 있습니다 . 이 경우 polly 또는 다른 라이브러리가 처리 할 수 ​​있도록 예외를 발생시키는 코드가 필요합니다.


1
동의, 반환에서 의미있는 메시지를 얻는 기능이없는 기본 코드.
LT

2
귀하의 버전은의 원래 구현과 다르게 작동합니다 EnsureSuccessStatusCode. 당신은 항상 response.Content(마지막으로 return;명령문 이후에도 항상 호출되기 때문에) 처분하고 추가 읽기를 위해 내용을 파괴합니다. 원래 구현은 상태 코드가 성공적인 결과를 나타내지 않는 경우에만 콘텐츠를 삭제합니다.
Lukas.Navratil

4
먼저 왜하지 않는 await response.Content.ReadAsStringAsync()한 다음 확인if (response.Content != null)
mafu

3
Polly는 이제 이러한 종류의 시나리오를 지원하기 위해 반환 결과와 예외를 처리합니다. HttpRequest호출 을 보호하도록 Polly를 구성하고 특정 예외 및 특정 HttpResponseCodes 를 처리하도록 정책을 구성 할 수 있습니다 . 여기 Polly readme
산악 여행자

2
response.Content메서드가 방금 호출되었을 때 어떻게 null이 될 수 있습니까?
Ian Warburton

1

동일한 메서드에서 예외를 처리하고 싶지 않을 때 ensureSuccessStatusCode를 사용합니다.

public async Task DoSomethingAsync(User user)
{
    try
    {
        ...
        var userId = await GetUserIdAsync(user)
        ...
    }
    catch(Exception e)
    {
        throw;
    }
}

public async Task GetUserIdAsync(User user)
{
    using(var client = new HttpClient())
    {
        ...
        response = await client.PostAsync(_url, context);

        response.EnsureSuccesStatusCode();
        ...
    }
}

GetUserIdAsync에서 발생한 예외는 DoSomethingAsync에서 처리됩니다.


0

아래는 제가 제안한 솔루션입니다. 유일한 결점은 ASP.NET Core 프레임 워크 리소스 관리자가 프레임 워크 내부에 있기 때문에 Microsoft의 국제화 된 메시지 문자열을 직접 재사용 할 수 없기 때문에 여기서는 그대로 영어 메시지 리터럴을 사용하고 있다는 것입니다.

장점

  • 5xx 서버 오류에 대한 내용을 기록합니다.
    • 경우에 따라 서버 오류는 실제로 종료 된 더 이상 사용되지 않는 엔드 포인트를 사용하는 클라이언트와 같이 위장 된 클라이언트 오류입니다.
  • 다음을 사용하여 통합 테스트를 작성할 때 오류를 쉽게 발견 할 수 있습니다. ConfigureTestContainer<T>

단점

  • 무능한.
    • 응답 내용을 읽고 내용이 너무 길면 클라이언트 속도가 느려집니다. 소프트 실시간 응답 요구 사항이있는 일부 클라이언트의 경우이 지터가 허용되지 않을 수 있습니다.
  • 오류 로깅 및 모니터링에 대한 잘못된 책임.
    • 이것이 5xx 서버 오류 인 경우 클라이언트가 잘못한 것이 없기 때문에 클라이언트가 신경을 쓰는 이유는 무엇입니까? 그냥 전화 해response.EnsureSuccessStatusCode(); 서버가 처리하도록하십시오.
    • 내부 서버 오류가있을 때 서버 오류 로그를 확인하는 것이 어떻습니까?
  • Content상태를 확인하기 전에 속성을 읽어야합니다 . 이것이 바람직하지 않은 상황이있을 수 있으며 그중 하나는 비 효율성입니다.

용법

using (var requestMessage = new HttpRequestMessage(HttpMethod.Post, "controller/action"))
{
  using (var response = await HttpClient.SendAsync(requestMessage))
  {
    var content = await response.Content.ReadAsStringAsync();
    response.EnsureSuccessStatusCode2(content);
    var result = JsonConvert.DeserializeObject<ResponseClass>(content);
  }
}

API

    public static class HttpResponseMessageExtensions
    {
        public static void EnsureSuccessStatusCode2(this HttpResponseMessage message, string content = null)
        {
            if (message.IsSuccessStatusCode)
                return;
            var contentMessage = string.IsNullOrWhiteSpace(content) ? string.Empty : $"Content: {content}";
            throw new HttpRequestException(string.Format(
                System.Globalization.CultureInfo.InvariantCulture,
                "Response status code does not indicate success: {0} ({1}).{2}",
                (int)message.StatusCode,
                message.ReasonPhrase,
                contentMessage)
                );
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.