使用 HttpCompletionOption.ResponseHeadersRead 的 HttpClient 超时 [英] HttpClient timeout using HttpCompletionOption.ResponseHeadersRead
问题描述
.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屋!