簡體   English   中英

使用RestSharp時如何慣用地處理HTTP錯誤代碼?

[英]How to idiomatically handle HTTP error codes when using RestSharp?

我正在使用RestSharp構建HTTP API客戶端,並且我注意到當服務器返回HTTP錯誤代碼(未授權401,未找到404,內部服務器錯誤500等)時, RestClient.Execute()不會引發異常-相反,我獲得了具有null .Data屬性的有效RestResponse 我不想在API客戶端中手動檢查每個可能的HTTP錯誤代碼-RestSharp是否提供了一種更好的將這些錯誤傳遞到客戶端應用程序的方法?

進一步的細節。 RestSharp公開一個Response.ErrorException屬性-如果RestClient.Execute<T>()調用引起任何異常,它將通過ErrorException屬性公開而不是拋出該異常。 他們的文檔包括以下示例:

// TwilioApi.cs
public class TwilioApi {
    const string BaseUrl = "https://api.twilio.com/2008-08-01";

    public T Execute<T>(RestRequest request) where T : new()
    {
    var client = new RestClient();
    client.BaseUrl = BaseUrl;
    client.Authenticator = new HttpBasicAuthenticator(_accountSid, _secretKey);
    request.AddParameter("AccountSid", _accountSid, ParameterType.UrlSegment); // used on every request
    var response = client.Execute<T>(request);

    if (response.ErrorException != null)
    {
        const string message = "Error retrieving response.  Check inner details for more info.";
        var twilioException = new ApplicationException(message, response.ErrorException);
        throw twilioException;
    }
    return response.Data;
    }

}

我在代碼中采用了這種模式,但是我的API服務器返回了401 Unauthorized ,但是ErrorException屬性仍然為null。 可以看到 RestResponse調試觀察 RestResponse.StatusCodeRestResponse.StatusDescription屬性中的未授權狀態代碼和錯誤消息-但是對於為何未授權響應不會導致填充ErrorException字段的原因,我感到困惑。

在嘗試為RestSharp WebAPI客戶端創建通用錯誤處理程序時遇到了相同的問題。 鑒於以下擴展方法:

public static class RestSharpExtensionMethods
{
    public static bool IsSuccessful(this IRestResponse response)
    {
        return response.StatusCode.IsSuccessStatusCode()
            && response.ResponseStatus == ResponseStatus.Completed;
    }

    public static bool IsSuccessStatusCode(this HttpStatusCode responseCode)
    {
        int numericResponse = (int)responseCode;
        return numericResponse >= 200
            && numericResponse <= 399;
    }
}

我提出了一個要求將響應反序列化的請求:

public async Task<ResponseModel<TResponse>> PerformRequestAsync<TResponse>(IRestRequest request)
{
    var response = await _client.ExecuteTaskAsync<ResponseModel<TResponse>>(request);
    ResponseModel<TResponse> responseData;

    if (response.IsSuccessful())
    {
        responseData = response.Data;
    }
    else
    {
        string resultMessage = HandleErrorResponse<TResponse>(request, response);

        responseData = new ResponseModel<TResponse>         
        {
            Success = false,
            ResultMessage = resultMessage
        };
    }

    return responseData;
}

但是,在測試過程中,我發現沒有針對這種情況配置錯誤處理時,當請求未映射的URL時,我的網絡服務返回了HTML格式的404頁面。 這導致response.ErrorException屬性包含以下字符串:

引用未聲明的實體“ nbsp”。 第n行,位置m。

顯然,RestSharp嘗試將響應解析為XML,即使內容類型為text / html。 也許我會為此向RestSharp提出問題。

當然,在生產環境中,調用自己的服務時永遠都不會收到404,但是我希望此客戶端能夠徹底且可重用。

因此,我可以想到兩種解決方案:

  • 檢查狀態碼並顯示說明
  • 確保服務返回一個可以解析的錯誤對象

前者很容易做到。 HandleErrorResponse()我根據狀態碼的數值構建結果消息(用戶可顯示)和錯誤字符串(可記錄):

public string HandleErrorResponse(IRestRequest request, IRestResponse response)
{
    string statusString = string.Format("{0} {1} - {2}", (int)response.StatusCode, response.StatusCode, response.StatusDescription);
    string errorString = "Response status: " + statusString;

    string resultMessage = "";
    if (!response.StatusCode.IsScuccessStatusCode())
    {
        if (string.IsNullOrWhiteSpace(resultMessage))
        {
            resultMessage = "An error occurred while processing the request: "
                          + response.StatusDescription;
        }
    }
    if (response.ErrorException != null)
    {
        if (string.IsNullOrWhiteSpace(resultMessage))
        {
            resultMessage = "An exception occurred while processing the request: "
                          + response.ErrorException.Message;
        }
        errorString += ", Exception: " + response.ErrorException;
    }

    // (other error handling here)

    _logger.ErrorFormat("Error response: {0}", errorString);

    return resultMessage;
}

現在,由於我的API響應始終包裝在我制作的ResponseModel<T> ,因此我可以設置一個異常過濾器和一個NotFound路由,以返回帶有ResultMessage屬性中的錯誤或異常消息的可解析響應模型:

public class HandleErrorAttribute : ExceptionFilterAttribute
{
    public override void OnException(HttpActionExecutedContext context)
    {
        // (log context.Exception here)

        context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, new ResponseModel<object>
        {
            Success = false,
            ResultMessage = "An exception occurred while processing the request: " + context.Exception.Message
        });
    }
}

和:

public class ErrorController : ApiController
{
    public HttpResponseMessage Handle404()
    {
        const string notFoundString = "The requested resource could not be found";

        var responseMessage = Request.CreateResponse(HttpStatusCode.NotFound, new ResponseModel<object>
        {
            Success = false,
            ResultMessage = notFoundString
        });

        responseMessage.ReasonPhrase = notFoundString;

        return responseMessage;
    }
}

這樣,我的服務響應始終可以由RestSharp解析,並且我可以使用通用的日志記錄方法:

public string HandleErrorResponse<TResponseModel>(IRestRequest request, IRestResponse<<ResponseModel<TResponseModel>> response)

並將實際響應記錄在// (other error handling here)如果有的話,在// (other error handling here)

if (response.Data != null && !string.IsNullOrWhiteSpace(response.Data.ResultMessage))
{
    resultMessage = response.Data.ResultMessage;
    errorString += string.Format(", Service response: \"{0}\"", response.Data.ResultMessage);
}

RestSharp添加了布爾屬性IRestResponse.IsSuccessful ,它涵蓋了您的用例。 我找不到任何有關此屬性的文檔,但這是定義該屬性的method的那一行

有趣的是,RestSharp認為代碼200-299成功,而CodeCaster認為代碼200-399成功。

檢查成功代碼,並在成功之外獲得其他任何代碼,則拋出或報告錯誤就足夠了。 這通常意味着在每個請求之后檢查HTTP狀態200。 如果創建新資源,則應該獲得狀態201。

對於大多數API /框架,如果沒有其他錯誤,則看到任何其他狀態代碼是非常不尋常的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM