【问题标题】:Cancellation token sometimes doesnt cancel HttpRequest取消令牌有时不会取消 HttpRequest
【发布时间】:2019-11-15 17:49:22
【问题描述】:

我的客户端应用程序向服务器发出 http 请求。如果服务器响应时间超过 10 秒,我希望请求超时。如果请求花费的时间超过 5 秒但成功了,我会记录响应时间。大多数时候一切都像我预期的那样工作。但有时它不会。应用程序阻塞了很长时间,之后我的日志消息显示“请求占用:00:01:20.1234567。被取消?假”,这意味着令牌没有被取消,也没有应用 httpClient 超时。有时它的“请求接受:00:01:20.1234567。被取消?是的”这表明令牌已被取消,但 httpClient 忽略了它。这种行为的原因可能是什么?

我正在运行 aspnet core 2.2 应用程序。我使用单个 tcp 连接同时发出多个并发 http 请求。我尝试在 httpClient 上设置超时属性。我尝试自己创建 CancellationTokenSource 并取消令牌。大多数情况下,应用程序都按预期工作。

using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;

namespace MyNamespace.MyClass
{
    public class MyClass
    {
        private HttpClient _httpClient = new HttpClient()
        {
            Timeout = TimeSpan.FromSeconds(10)
        };

        public string SendRequest()
        {
            var request = new HttpRequestMessage();
            request.RequestUri = new Uri("mockMyUri");
            request.Method = HttpMethod.Post;
            request.Content = new StringContent("myContent");
            request.Content.Headers.ContentType = new MediaTypeHeaderValue("text/xml");
            var cts = new CancellationTokenSource();
            cts.CancelAfter(TimeSpan.FromSeconds(10));
            Stopwatch stopwatch = new Stopwatch();
            stopwatch.Start();
            var response = _httpClient.SendAsync(request, cts.Token).Result;
            stopwatch.Stop();
            if (!response.IsSuccessStatusCode)
                throw new Exception();
            var content = response.Content.ReadAsStringAsync().Result;
            if (stopwatch.Elapsed > TimeSpan.FromSeconds(5))
                Console.WriteLine($"Request took: {stopwatch.Elapsed}. Was cancelled? {cts.IsCancellationRequested}");
            return content;
        }
    }
}```

【问题讨论】:

    标签: asp.net-core .net-core dotnet-httpclient cancellationtokensource cancellation-token


    【解决方案1】:

    CancellationTokenCancellationTokenSource 用于异步操作。 但是您对_httpClient 的调用,即使它正在调用SendAsync,也在同步处理,因为没有**await** 关键字,而您正在使用.Result(这使它等待接收结果)。 您的函数和对 _httpClient 的调用应该是这样的:

    public async Task<string> SendRequest() 
    {
     ...
      var responseTask = await _httpClient.SendAsync(request, cts.Token);
      var response = responseTask.Result;
     ...
     // and the same for content:
      var contentTask = await response.Content.ReadAsStringAsync();
      return contentTask;
    }
    

    【讨论】:

    • 感谢您的回复。不幸的是,您建议的代码没有解决我的问题。我最终应用了一种解决方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2015-06-19
    相关资源
    最近更新 更多