如何从 HttpRequestException 获取 StatusCode?

我可能漏掉了一些显而易见的东西。

我正在使用 HttpClient,它抛出消息字符串中包含 StatusCodeHttpRequestException

我怎样才能进入 StatusCode


编辑 : 更多信息,我匆忙写了这个问题。

我正在使用 HttpClient访问 WebApi 项目中的另一个 API。是的,我知道为什么我要打电话给 EnsureSuccessStatusCode()。我想传播一些错误下游,如404和403。

所有我想要的是始终如一地使用自定义 ExceptionFilterAttributeHttpRequestException转换为 HttpResponseException

不幸的是,HttpRequestException没有任何额外的信息,我可以使用除了消息。我希望以原始(int 或 enum)形式发现 StatusCode

看来我也可以:

  1. 使用消息切换状态代码(bleh)
  2. 或者创建我自己版本的 EnsureSuccess StatusCode 并抛出实际可用的异常。
95385 次浏览

Status code was passed as part of a string to HttpRequestException so that you cannot recover it from such exceptions alone.

The design of System.Net.Http requires you to access HttpResponseMessage.StatusCode instead of waiting for the exception.

http://msdn.microsoft.com/en-us/library/system.net.http.httpresponsemessage(v=vs.110).aspx

If you are now following the Microsoft guide, make sure you understand clearly why it asks you to call HttpResponseMessage.EnsureSucessStatusCode. If you don't call that function, there should be no exception.

As mentioned by others as well it's not a good practice to get the StatusCode from HttpRequestException, the same can be done beforehand with HttpResponseMessage.StatusCode after checking HttpResponseMessage.IsSuccessStatusCode

Anyhow if due to some constraint/requirement one has to read StatusCode, There can be two solution

  1. Extended the HttpResponseMessage with your custom exception explained here
  2. Hack on the HttpRequestException.ToString to get the StatusCode, As the message is a constant post fixed by StatusCode and Repharse.

Below is the code in System.Net.Http.HttpResponseMessage Where SR.net_http_message_not_success_statuscode ="Response status code does not indicate success: {0} ({1})."

public HttpResponseMessage EnsureSuccessStatusCode()
{
if (!this.IsSuccessStatusCode)
{
if (this.content != null)
{
this.content.Dispose();
}
throw new HttpRequestException(string.Format(CultureInfo.InvariantCulture, SR.net_http_message_not_success_statuscode, new object[]
{
(int)this.statusCode,
this.ReasonPhrase
}));
}
return this;
}

For what its worth, this guy did something clever: https://social.msdn.microsoft.com/Forums/vstudio/en-US/dc9bc426-1654-4319-a7fb-383f00b68def/c-httpresponsemessage-throws-exception-httprequestexception-webexception-the-remote-name?forum=csharpgeneral

In the case where I needed an exception status property, I can do this:

catch (HttpRequestException requestException)
{
if (requestException.InnerException is WebException webException && webException.Status == WebExceptionStatus.NameResolutionFailure)
{
return true;
}


return false;
}

This has worked for me

var response = ex.Response;
var property = response.GetType().GetProperty("StatusCode");
if ( property != null && (HttpStatusCode)property.GetValue(response) == HttpStatusCode.InternalServerError)

From .NET 5.0, HttpRequestException has a StatusCode property which will have a value if the exception represents a non-successful result, otherwise null. So you can use as follows:

try
{
// Your code
}
catch (HttpRequestException httpRequestException)
{
if ((int)httpRequestException.StatusCode == 401)
{
// Show unauthorized error message
}
else
{
// Other error message
}
}

For more details are here

For .Net Core 3.1 I could not make use of TanvirArjel or Lex Li's solution. So I went with manually calling the HttpClient's GetHttpAsync method and interrogating the Http status code myself. If the status code returns "OK" I process the HttpClient's Content property for the returned Html.

public async Task<string> GetHtml(string url)
{
int retry = 3;


while (retry > 0)
{
retry = retry - 1;


try
{
var result = await client.GetAsync(url);
if (result.StatusCode != HttpStatusCode.OK)
{
switch (result.StatusCode)
{
case HttpStatusCode.BadGateway:
case HttpStatusCode.BadRequest:
case HttpStatusCode.Forbidden:
case HttpStatusCode.ServiceUnavailable:
case HttpStatusCode.GatewayTimeout:
{
Global.Report($"CustomHttpClient: Temporary issue detected. Pausing to allow time to resolve.");
// Wait for temporary issue to resolve
await Task.Delay(120000);
continue;
}
default:
{
throw new Exception($"CustomHttpClient: Error {result.StatusCode}.");
}
}
}
string response = await result.Content.ReadAsStringAsync();
return response;
}
catch (Exception ex)
{
throw new Exception($"CustomHttpClient: Error downloading page => {url}. " + ex);
}
}


throw new Exception($"CustomHttpClient: Temporary issue persists. Retries exhausted. Unable to download page => {url}.");
}

If what you need is to extract status code from HttpRequestException (eg: in a application exception handler), look at answers from others.

Otherwise you might take a look at HttpClient.GetAsync() method. Unlike methods like HttpClient.GetStringAsync() (which return simple data type and thrown and exception if something goes wrong), that one return you a HttpResponseMessage object everytime, regardless request success or failure.

From there you can check status code :

var response = await client.GetAsync(...);
if (!response.IsSuccessStatusCode)
{
var statusCode = response.StatusCode;
//throw an exception or something similar
}


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

in .Net 6

    try
{
return await _httpClient.GetFromJsonAsync<YourType>("<url>", cancellationToken);
}
catch (HttpRequestException e) when (e.StatusCode == HttpStatusCode.NotFound)
{
// handle 404
}