【问题标题】:httpClient.GetAsync() timeout exception, if application idle a long timehttpClient.GetAsync() 超时异常,如果应用程序空闲很长时间
【发布时间】:2020-09-23 09:35:31
【问题描述】:

我开发了C# .net 4.6.1 应用程序。 在应用程序中,我使用HttpClient 与我们的后端 API 进行通信。 随着时间的推移,应用程序不会向我们的后端发送请求(超时异常被捕获)。重新启动应用程序后发送请求。

这是我们代码的 sn-p。

class Program
{
  static void Main(string[] args)
  {
    MyClass myClass = GetAsync().Result;
  }

  private static async Task<MyClass> GetAsync()
  {
     MyClassResponse myClassResponse = await TestHttpClient.GetMyClassResponse();
    return MyClass.Create(myClassResponse);
  }
}
public static class TestHttpClient
{
   private static HttpClient _httpClient;

   public static void Init()
   {
     _httpClient = CreateHttpClient();
   }

   public static async Task<MyClassResponse> GetMyClassResponse()
   {
      HttpResponseMessage response = await GetRequestAsync("https://....");
      return await ParseToMyClassResponse<MyClassResponse>(response);
   }

   private static HttpClient CreateHttpClient()
   {
      HttpClient client = new HttpClient();
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token .....");
      client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
      client.Timeout = TimeSpan.FromMilliseconds(10000);
      return client;
    }

    private static async Task<HttpResponseMessage> GetRequestAsync(string url)
   {
        try
        {
           return await _httpClient.GetAsync(new Uri(url));
         }
         catch (TaskCanceledException)
         {
          return new HttpResponseMessage(HttpStatusCode.RequestTimeout);
         }
    }

    private static async Task<T> ParseToMyClassResponse<T>(HttpResponseMessage response) where T : MyClassResponse, new()
        {
            T myClassResponse;
            try
            {
                string content = await response.Content.ReadAsStringAsync();
                response.EnsureSuccessStatusCode();
                myClassResponse = JsonConvert.DeserializeObject<T>(content);
                           }
            catch (Exception ex)
            {
                myClassResponse = new T();
            }

            response.Dispose();
            return myClassResponse;
        }
}

我做错了什么?

【问题讨论】:

  • 你好@aram你能和我们分享一下错误信息和代码状态吗?

标签: c# .net async-await dotnet-httpclient get-request


【解决方案1】:

我看到的几件事:

首先,您的异常处理程序忽略异常并抛出新异常。为您的TaskCanceledException 分配一个变量,并在抛出一个新异常之前记录该实际异常。内部异常可能会为您提供有关所发生情况的更多信息。

catch (TaskCancelledException e))
{
    Debug.WriteLine(e);
    //do whatever else
}

旁注:使用new HttpResponseMessage(HttpStatusCode.RequestTimeout) 可能不是最合适的。这使得看起来服务器返回了408 Request Timeout。事实并非如此。

会引发TaskCanceledException 的超时是客户端发送请求,但在预期时间(默认为 30 秒)内未收到来自服务器的响应。

如果确实发生了这种超时,那么您可能需要查看Wireshark 或Fiddler 之类的内容来验证请求是否正在发送。然后,您必须弄清楚该请求与重新启动应用程序后发送的请求之间有什么不同。

例如,您的令牌是否已过期并且重新启动您的应用程序请求一个新令牌? (这不应该导致超时,但如果服务器代码写得不好,它可以)

【讨论】:

  • 感谢您的快速响应。此错误仅由我们的一位客户产生。我将尝试在他们的计算机上安装 Fiddler 并分析请求。今天我将添加日志记录并分享错误消息和状态。
【解决方案2】:

我添加了日志记录并收到以下错误:

System.Threading.Tasks.TaskCanceledException · 任务被取消。

System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
TestHttpClient+<GetRequestAsync>d__20.MoveNext()

我使用 Fiddler 查看了请求,得到了以下结果

  1. 在正常模式下,提琴手显示 2 个请求

    • Result=200,Protocol=HTTP,Host = Tunnel to,Url = api.example.com:443

      在 SyntaxView 选项卡中:找到了与 SSLv3 兼容的 ClientHello 握手。 Fiddler 提取了以下参数。

    • 结果=200,协议=HTTPS,主机=api.example.com,网址=/test

  2. 在失败模式下,Fiddler 仅显示 1 个请求

    • 结果=200,协议=HTTP,主机=隧道,网址=api.example.com:443,

      在 SyntaxView 选项卡中: 客户收到通知后 建立CONNECT,发送数据失败

我想更正一下。实际上,我是这样使用 Init() 方法的。

public static class TestHttpClient
{
   private static HttpClient _httpClient;

  public static void Init()
  {
    ServicePointManager.SecurityProtocol |= (SecurityProtocolType.Ssl3 | 
              SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | 
                                            SecurityProtocolType.Tls);
    ServicePointManager.DefaultConnectionLimit = 10;
    _httpClient = CreateHttpClient();
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-28
    • 2015-09-28
    相关资源
    最近更新 更多