使用RestSharp时如何以惯用方式处理HTTP错误代码?

我正在使用RestSharp构建HTTP API客户端,我注意到当服务器返回HTTP错误代码(401 Unauthorized,404 Not Found,500 Internal Server Error等)时, RestClient.Execute()不会抛出exception – 而是获得一个带有null .Data属性的有效RestResponse 。 我不想在我的API客户端中手动检查每个可能的HTTP错误代码 – RestSharp是否提供了将这些错误传递给我的客户端应用程序的更好方法?

更进一步的细节。 RestSharp公开Response.ErrorException属性 – 如果RestClient.Execute()调用导致任何exception,它将通过ErrorException属性公开而不是被抛出。 他们的文档包括以下示例:

 // TwilioApi.cs public class TwilioApi { const string BaseUrl = "https://api.twilio.com/2008-08-01"; public T Execute(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(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客户端创建一般error handling程序时遇到了同样的问题。 鉴于这些扩展方法:

 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> PerformRequestAsync(IRestRequest request) { var response = await _client.ExecuteTaskAsync>(request); ResponseModel responseData; if (response.IsSuccessful()) { responseData = response.Data; } else { string resultMessage = HandleErrorResponse(request, response); responseData = new ResponseModel { Success = false, ResultMessage = resultMessage }; } return responseData; } 

但是,在测试期间,我发现当我没有为该情况配置error handling时,我的web服务器在请求未映射的URL时返回了HTML格式的404页面。 这导致response.ErrorException属性包含以下字符串:

引用未声明的实体'nbsp'。 第n行,位置m。

显然,RestSharp试图将响应解析为XML,即使内容类型是text / html。 也许我会为此向RestSharp提出问题。

当然在生产中,在调用自己的服务时不应该得到404,但我希望这个客户端是彻底的和可重用的。

所以我能想到两个解决方案:

  • 检查状态代码并显示说明
  • 确保该服务返回可以解析的错误对象

前者很容易完成。 在HandleErrorResponse()我根据状态代码的数值构建结果消息(用户可呈现)和错误字符串(loggable):

 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中,我可以设置一个exceptionfilter和一个NotFound路由来返回一个可解析的响应模型,其中包含ResultMessage属性中的错误或exception消息:

 public class HandleErrorAttribute : ExceptionFilterAttribute { public override void OnException(HttpActionExecutedContext context) { // (log context.Exception here) context.Response = context.Request.CreateResponse(HttpStatusCode.InternalServerError, new ResponseModel { 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 { Success = false, ResultMessage = notFoundString }); responseMessage.ReasonPhrase = notFoundString; return responseMessage; } } 

这样我的服务响应总是可以被RestSharp解析,我可以使用通用的日志记录方法:

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

并记录实际响应// (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); } 

它应该足以检查成功代码,如果除了成功之外还得到任何其他代码,则抛出或报告错误。 这通常意味着在每次请求后检查HTTP状态200。 如果您创建新资源,则应该期望Status 201。

对于大多数API /框架,如果没有出现任何问题,除了这些之外,看到任何其他状态代码是非常不寻常的。

RestSharp添加了布尔属性IRestResponse.IsSuccessful ,它涵盖了您的用例。 我找不到任何引用此属性的文档,但这里是定义属性方法的行 。

值得注意的是,RestSharp认为代码200-299是成功的,而CodeCaster认为代码200-399是成功的。