Cách sử dụng Mã EnsureSuccessStatusCode và xử lý HttpRequestException mà nó ném


104

Mô hình sử dụng của là HttpResponseMessage.EnsureSuccessStatusCode()gì? Nó loại bỏ Nội dung của tin nhắn và ném đi HttpRequestException, nhưng tôi không biết cách xử lý nó theo chương trình có khác gì so với thông thường Exception. Ví dụ, nó không bao gồm HttpStatusCode, điều này sẽ rất hữu ích.

Có cách nào để lấy thêm thông tin về nó không? Có ai có thể hiển thị kiểu sử dụng có liên quan của cả hai EnsureSuccessStatusCode()và HttpRequestException không?

Câu trả lời:


156

Cách sử dụng thành ngữ của EnsureSuccessStatusCodelà để xác minh một cách ngắn gọn sự thành công của một yêu cầu, khi bạn không muốn xử lý các trường hợp thất bại theo bất kỳ cách cụ thể nào. Điều này đặc biệt hữu ích khi bạn muốn nhanh chóng tạo mẫu một ứng dụng khách.

Khi bạn quyết định muốn xử lý các trường hợp thất bại theo một cách cụ thể, đừng làm những việc sau.

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

Điều này ném ra một ngoại lệ chỉ để bắt nó ngay lập tức, điều này không có ý nghĩa gì. Tài IsSuccessStatusCodesản của HttpResponseMessagelà ở đó cho mục đích này. Hãy làm như sau.

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

1
Có cách nào để lấy mã trạng thái số nguyên thực không? khi tôi thử điều này, tôi nhận được một chuỗi chẳng hạn như "NotFound" thay vì mã trạng thái 404.
NickG

12
@NickG (int)response.StatusCode(Xem msdn.microsoft.com/en-us/library/… )
Timothy Shields

1
Lưu ý, HttpRequestException mặc định được tạo bởi EnsureSuccessStatusCode () sẽ có cụm từ lý do. Nhưng bạn vẫn có thể truy cập thuộc tính đó trong phản hồi nếu nó không thành công.
Stefan Zvonar

@StefanZvonar Tôi không thể tìm thấy Cụm từ lý do trong ngoại lệ như những gì bạn đã viết.
KansaiRobot

1
@NickG Bạn có thể sử dụng (int) response.StatusCode để nhận giá trị số cho Mã trạng thái HTTP
Henrik Holmgaard Høyer

95

Tôi không thích EnsureSuccessStatusCode vì nó không trả về bất kỳ thứ gì ít ỏi. Đó là lý do tại sao tôi đã tạo tiện ích mở rộng của riêng mình:

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;
    }
}

có thể tìm thấy mã nguồn cho EnsureSuccessStatusCode của Microsoft tại đây

Phiên bản đồng bộ dựa trên liên kết 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);
}

Điều tôi không thích về IsSuccessStatusCode là nó không thể tái sử dụng một cách "độc đáo". Ví dụ: bạn có thể sử dụng thư viện như polly để lặp lại một yêu cầu trong trường hợp mạng có vấn đề. Trong trường hợp đó, bạn cần mã của mình để tăng ngoại lệ để polly hoặc một số thư viện khác có thể xử lý nó ...


1
đồng ý, mã mặc định thiếu tính năng để nhận một thông điệp có ý nghĩa từ sự trở lại.
LT

2
Phiên bản của bạn hoạt động khác với triển khai ban đầu của EnsureSuccessStatusCode. Bạn luôn loại bỏ response.Content(vì cuối cùng luôn được gọi ngay cả sau return;câu lệnh) và nó phá hủy nội dung để đọc sau này. Việc triển khai ban đầu chỉ loại bỏ nội dung khi mã trạng thái không cho biết kết quả thành công.
Lukas.Navratil

4
Tôi không hiểu tại sao bạn trước tiên await response.Content.ReadAsStringAsync()và sau đó kiểm traif (response.Content != null)
mafu

3
Polly hiện xử lý các kết quả trả về cũng như các trường hợp ngoại lệ, một cách chính xác để hỗ trợ cho loại tình huống này. Bạn có thể định cấu hình Polly để bảo vệ HttpRequestcác cuộc gọi và định cấu hình cả chính sách để xử lý một số trường hợp ngoại lệ và một số trường hợp nhất định HttpResponseCode. Xem ví dụ trong bài đọc Polly tại đây
du khách miền núi

2
Làm thế nào có thể response.Contentlà null khi nó vừa có một phương thức được gọi trên nó?
Ian Warburton

1

Tôi sử dụng EnsureSuccessStatusCode khi tôi không muốn xử lý Ngoại lệ trên cùng một phương pháp.

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();
        ...
    }
}

Ngoại lệ được ném trên GetUserIdAsync sẽ được xử lý trên DoSomethingAsync.


0

Dưới đây là giải pháp đề xuất của tôi. Lỗ hổng duy nhất là vì trình quản lý tài nguyên khung ASP.NET Core là nội bộ của khung, tôi không thể trực tiếp sử dụng lại các chuỗi thông báo đã quốc tế hóa của Microsoft, vì vậy tôi chỉ sử dụng nguyên văn thông báo bằng tiếng Anh ở đây.

Ưu điểm

  • Ghi lại nội dung cho lỗi máy chủ 5xx
    • Đôi khi, lỗi máy chủ thực sự là lỗi máy khách ngụy tạo, chẳng hạn như máy khách sử dụng điểm cuối không dùng nữa cuối cùng đã bị tắt.
  • Giúp phát hiện lỗi dễ dàng hơn khi viết các bài kiểm tra tích hợp bằng cách sử dụng ConfigureTestContainer<T>

Nhược điểm

  • Không hiệu quả.
    • Nếu bạn đọc nội dung phản hồi, và nội dung rất dài, bạn sẽ làm chậm khách hàng. Đối với một số máy khách, với các yêu cầu phản hồi thời gian thực mềm, hiện tượng chập chờn này có thể không được chấp nhận.
  • Không chịu trách nhiệm về việc ghi và giám sát lỗi.
    • Nếu đây là lỗi máy chủ 5xx, tại sao máy khách lại quan tâm, vì máy khách không làm gì sai? Chỉ cần gọi response.EnsureSuccessStatusCode();và để máy chủ xử lý.
    • Tại sao không chỉ kiểm tra nhật ký lỗi máy chủ khi có Lỗi máy chủ nội bộ?
  • Yêu cầu đọc thuộc Contenttính trước khi kiểm tra trạng thái. Có thể có những tình huống không mong muốn, một trong số đó là sự kém hiệu quả.

Sử dụng

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)
                );
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.