c# - 使用 HttpCompletionOption.ResponseHeadersRead 的 HttpClient 超时
问题描述
Windows 上的 .NET Core 3.1 控制台应用程序,我试图弄清楚为什么在使用HttpCompletionOption.ResponseHeadersReadhttpClient.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);
}
}
HttpCompletionOption
我从这篇很棒的文章中
了解到: https ://www.stevejgordon.co.uk/using-httpcompletionoption-responseheadersread-to-improve-httpclient-performance-dotnet
更新
使用下面的@StephenCleary 答案将cancellationToken 传递到CopyToAsync
现在可以按预期工作的方法中。
我在下面包含了更新的代码,它显示了将 a MemoryStream
then 复制到一个字符串中,我发现很难找到如何去做。对于我的用例,这很好。
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
完整”,所以它是完整的。所以问题在于它不适用于从流中读取。
我建议使用Polly 的 Timeout而不是HttpClient.Timeout
; Polly 是一个通用库,可用于使任何操作超时。
如果此时不想使用 Polly,可以将 传递CancellationToken
给Stream.CopyToAsync
。
推荐阅读
- javascript - 如何用另一个数组值替换javascript中的数组值?
- azure - Azure 托管应用程序 - 带有应用程序链接的 ViewDefinition.json 操作
- javascript - 单击按钮时如何将所有其他布尔值切换为false
- mysql - 检查值是否存在于另一个(连接的)表中并相应地在结果中填写列
- linux - for 循环在 bash 中创建的整数比预期的要多
- jenkins - gitlab gui 不显示从阶段测试返回的 jenkinsfile 报告
- python - 从列表中创建可滚动区域
- windows - 如何使用 NDIS 过滤器驱动程序从协议层重定向 TCP 数据包?
- amazon-web-services - AWS Elastic Beanstalk 日志?访问更详细的日志?
- spring-boot - 是否可以使用 Ehcache 3.x 实现缓存刷新行为?