RestSharpを使用してHTTP APIクライアントを構築していますが、サーバーがHTTPエラーコード(401 Unauthorized、404 Not Found、500 Internal Server Errorなど)を返すと、RestClient.Execute()
が例外をスローしません-代わりに、_.Data
_プロパティがnullの有効な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のままです。私canを参照 _RestResponse.StatusCode
_プロパティと_RestResponse.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が要求されたときに、WebサービスがHTML形式の404ページを返すことがわかりました。これにより、_response.ErrorException
_プロパティに次の文字列が含まれます。
宣言されていないエンティティ「nbsp」への参照。行n、位置m。
明らかにコンテンツタイプがtext/htmlであるにもかかわらず、RestSharpは応答をXMLとして解析しようとしました。たぶん、これについてRestSharpに問題を報告します。
もちろん、本番環境では、独自のサービスを呼び出すときに404を取得することはありませんが、このクライアントを徹底して再利用できるようにしたいと思います。
だから私が考えることができる2つの解決策があります:
前者は非常に簡単に実行できます。 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)
に記録します。
_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
が追加されました。このプロパティを参照しているドキュメントは見つかりませんでしたが、 プロパティのメソッドを定義する行 です。
興味深いことに、RestSharpはコード200-299を成功と見なし、CodeCasterはコード200-399を成功と見なします。
成功コードを確認し、成功以外のコードを取得した場合は、エラーをスローまたは報告するだけで十分です。これは通常、リクエストごとにHTTPステータス200をチェックすることを意味します。新しいリソースを作成する場合は、ステータス201になるはずです。
ほとんどのAPI /フレームワークでは、何も問題がなければ、これら以外のステータスコードが表示されることは非常にまれです。