【问题标题】:C# HttpClient.GetAsync ignore HttpCompletionOption.ResponseHeadersReadC# HttpClient.GetAsync 忽略 HttpCompletionOption.ResponseHeadersRead
【发布时间】:2021-06-30 10:47:07
【问题描述】:

我在使用 C#HttpClient 时遇到了一个奇怪的情况。我正在尝试使用GetAsync 中的HttpCompletionOption.ResponseHeadersRead 选项来尽快获取没有内容的响应标头。但是在下载文件时,我在await GetAsync,直到整个内容都通过网络下载(我用 Fiddler 进行了检查)。我附上了一个下载 1Gb 测试文件的示例代码。示例应用程序将在await client.GetAsync 中挂起,直到通过网络接收到所有文件内容。当标头完成接收并且不等待通过网络完成内容传输时,如何重新获得控制权?

using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

public class Program
    {
        private const int HttpBufferSize = 81920;

        private static async Task Main(string[] args)
        {
            var url = new Uri("http://212.183.159.230/1GB.zip");

            await DownloadFileAsync(@"C:\1GB.zip", url, CancellationToken.None).ConfigureAwait(false);
        }

        private static async Task DownloadFileAsync(string filePath, Uri fileEndpoint,
            CancellationToken token)
        {
            using var client = new HttpClient();

            using var response = await client.GetAsync(fileEndpoint, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false);

            response.EnsureSuccessStatusCode();

            await using var contentStream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);
            await using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);
            await contentStream.CopyToAsync(stream, HttpBufferSize, token).ConfigureAwait(false);
        }
    }

【问题讨论】:

  • 你应该使用HEAD而不是GET请求。
  • @Riddell 这就是 httpcompletionoption 在 Get 调用中所做的我认为 stackoverflow.com/questions/16416699/…
  • @sommmen 从内存中,GetAsync 始终是 GET 请求,因为它是 SendAsyncHttpMethod.Get 的包装器。
  • @Riddell 感谢您的解释!
  • 我无法使用提供的代码重现这一点。对我来说,代码在GetAsync 上没有等待很长时间;正如预期的那样,它在CopyToAsync 上等待了很长时间。有没有可能是 Fiddler 误导了你?

标签: c# dotnet-httpclient


【解决方案1】:

您正在发送GET 请求。如果您只需要标头,那么您可以使用HEAD 请求。 HttpClient 的示例:

client.SendAsync(new HttpRequestMessage(HttpMethod.Head, url))

警告:服务器可以阻止 HEAD 请求,因此请确保妥善处理。例如,如果响应失败,则回退到 GET 请求,但这会以速度为代价。

【讨论】:

  • 我不仅需要接收标头,因此我不能只执行 Head 请求。另外,在我的任务中,需要在获取标题和内容之间执行操作,因此无法执行Head然后Get。
【解决方案2】:

我已经确定了这种行为的原因。原因是Fiddler。它充当代理,似乎没有重定向部分收到的响应。为了检查这一点,我为每个操作添加了控制台输出:

Console.WriteLine($"Start GetAsync - {DateTime.Now}");
using var response = await client.GetAsync(fileEndpoint, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false);
Console.WriteLine($"End GetAsync - {DateTime.Now}");

response.EnsureSuccessStatusCode();

await using var contentStream = await response.Content.ReadAsStreamAsync(token).ConfigureAwait(false);
await using var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);

Console.WriteLine($"Start CopyToAsync - {DateTime.Now}");
await contentStream.CopyToAsync(stream, HttpBufferSize, token).ConfigureAwait(false);
Console.WriteLine($"End CopyToAsync - {DateTime.Now}");

运行程序Fiddler的结果:

Start GetAsync - 30.06.2021 17:46:03
End GetAsync - 30.06.2021 17:46:49
Start CopyToAsync - 30.06.2021 17:46:49
End CopyToAsync - 30.06.2021 17:46:51

没有Fiddler的结果:

Start GetAsync - 30.06.2021 17:38:32
End GetAsync - 30.06.2021 17:38:32
Start CopyToAsync - 30.06.2021 17:38:32
End CopyToAsync - 30.06.2021 17:39:48

结论:小心代理

【讨论】:

  • 遇到了同样的问题。感谢您的信息
猜你喜欢
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 2016-07-21
  • 2012-01-18
相关资源
最近更新 更多