【问题标题】:HttpClient timeout using HttpCompletionOption.ResponseHeadersRead使用 HttpCompletionOption.ResponseHeadersRead 的 HttpClient 超时
【发布时间】:2020-07-20 11:56:32
【问题描述】:

Windows 上的 .NET Core 3.1 控制台应用程序,我试图弄清楚为什么在使用 HttpCompletionOption.ResponseHeadersRead 后获取内容时 httpClient.Timeout 似乎不起作用

static async Task Main(string[] args)
{
    var httpClient = new HttpClient();

    // if using HttpCompletionOption this timeout doesn't work
    httpClient.Timeout = TimeSpan.FromSeconds(5);

    var uri = new Uri("http://brokenlinkcheckerchecker.com/files/200MB.zip");

    // will not timeout
    //using var httpResponseMessage = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead);

    // will timeout after 5s with a TaskCanceledException
    var httpResponseMessage = await httpClient.GetAsync(uri);

    Console.WriteLine($"Status code is {httpResponseMessage.StatusCode}. Press any key to get content");
    Console.ReadLine();
    Console.WriteLine("getting content");

    var html = await httpResponseMessage.Content.ReadAsStringAsync();
    Console.WriteLine($"finished and length is {html.Length}");
}

也试过CancellationToken

// will not timeout
var cts = new CancellationTokenSource(5000);
using var httpResponseMessage = await httpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead,
 cts.Token);

ReadAsStreamAsync

// will not timeout
using (Stream streamToReadFrom = await httpResponseMessage.Content.ReadAsStreamAsync())
{
    string fileToWriteTo = Path.GetTempFileName();
    using (Stream streamToWriteTo = File.Open(fileToWriteTo, FileMode.Create))
    {
        await streamToReadFrom.CopyToAsync(streamToWriteTo);
    }
}

我从这篇很棒的文章中了解到HttpCompletionOptionhttps://www.stevejgordon.co.uk/using-httpcompletionoption-responseheadersread-to-improve-httpclient-performance-dotnet

更新 使用下面的@StephenCleary 答案将cancellationToken 传递给CopyToAsync 方法,现在可以按预期工作。

我在下面包含了更新的代码,它显示了复制到 MemoryStream 然后到一个字符串,我发现很难找到如何去做。对于我的用例,这很好。

string html;
await using (var streamToReadFrom = await httpResponseMessage.Content.ReadAsStreamAsync())
await using (var streamToWriteTo = new MemoryStream())
{
    await streamToReadFrom.CopyToAsync(streamToWriteTo, cts.Token);
    // careful of what encoding - read from incoming MIME
    html = Encoding.UTF8.GetString(streamToWriteTo.ToArray());
}

【问题讨论】:

  • 你为什么要在这里超时?
  • @PavelAnikhouski - 好问题!我对为什么使用 HttpCompletionOption 时超时行为似乎发生变化很感兴趣。我还在编写代码,即使客户端仍在成功下载内容,我也希望在 x 秒后引发 Http 异常。

标签: c# http .net-core


【解决方案1】:

我希望HttpClient.Timeout 仅适用于请求的GetAsync 部分。 HttpCompletionOption.ResponseHeadersRead 的意思是“在读取响应标头时考虑 Get 完成”,所以它是完整的。所以问题在于它不适用于从流中读取。

我建议使用Polly's Timeout 而不是HttpClient.Timeout; Polly 是一个通用库,可用于超时任何操作。

如果此时不想使用 Polly,可以将CancellationToken 传递给Stream.CopyToAsync

【讨论】:

  • 非常感谢。我现在用一个有效的答案更新了这个问题。下一步github.com/App-vNext/Polly 因为忘记了这个优秀的图书馆!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多