使用 HttpCompletionOption.ResponseHeadersRead 的 HttpClient 超时 [英] HttpClient timeout using HttpCompletionOption.ResponseHeadersRead

查看:145
本文介绍了使用 HttpCompletionOption.ResponseHeadersRead 的 HttpClient 超时的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

.NET Core 3.1 控制台应用程序在 Windows 上,我试图弄清楚为什么 httpClient.Timeout 在使用 HttpCompletionOption.ResponseHeadersRead

.NET Core 3.1 Console application on Windows, I'm trying to figure out why the httpClient.Timeout does not seem to be working when getting the content after using HttpCompletionOption.ResponseHeadersRead

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);
    }
}

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

I learned about HttpCompletionOption from this great article: https://www.stevejgordon.co.uk/using-httpcompletionoption-responseheadersread-to-improve-httpclient-performance-dotnet

更新使用下面的@StephenCleary 回答将取消令牌传递到 CopyToAsync 方法,现在按预期工作.

Update Using @StephenCleary answer below of passing the cancellationToken into the CopyToAsync method this now works as expected.

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

I've included the updated code below which shows copying into a MemoryStream then into a string, which I found tricky to find how to do. For my use case this is good.

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());
}

推荐答案

我希望 HttpClient.Timeout 仅适用于请求的 GetAsync 部分.HttpCompletionOption.ResponseHeadersRead 表示在读取响应标头时认为 Get 已完成",因此它是完整的.所以问题是它不适用于从流中读取.

I would expect HttpClient.Timeout to only apply to the GetAsync part of the request. HttpCompletionOption.ResponseHeadersRead means "consider the Get complete when the response headers are read", so it's complete. So the problem is that it just doesn't apply to reading from the stream.

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

I recommend using Polly's Timeout instead of HttpClient.Timeout; Polly is a generic library that can be used to timeout any operation.

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

If you don't want to use Polly at this time, you can pass the CancellationToken to Stream.CopyToAsync.

这篇关于使用 HttpCompletionOption.ResponseHeadersRead 的 HttpClient 超时的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆