首页 > 解决方案 > C# HttpClient 不处理 304/307 重定向

问题描述

我正在尝试让 HttpClient 从网站中提取网站图标,并且对于 99% 的情况,此代码按预期工作:

var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(10);

var response = await httpClient.GetAsync("https://www.tesco.com/favicon.ico");
response.EnsureSuccessStatusCode();

我在几个网站上发现我的 GetAsync 方法刚刚超时,我相信这与它的重定向有关。如果您在控制台应用程序中运行上述代码,则会在 10 秒后在 TaskCanceledException 和 IOException 中引发以下异常:

SocketException:由于线程退出或应用程序请求,I/O 操作已中止。

这个请求在 Postman 上工作得很好,我试过 https 和 http 都没有成功。访问该站点并使用 Chrome 的开发工具时,看起来如果您使用 http 而不是 https,它会返回 307 并将您重定向到 https 站点,然后返回 304。我不明白为什么 HttpClient 只是计时而不是给出有用的回应。

有什么办法可以让它工作吗?我错过了一些简单的东西吗?

更新 - 2021-01-29

我已经在多个不同的 .NET 版本上进行了尝试,发现这可能是 HttpClient 的一个错误,因为此代码适用于 .NET Core 2.0,但不适用于 .NET Core 2.1。

测试版本

标签: c#.net-coredotnet-httpclienthttp-redirect.net-5

解决方案


事实证明,这根本不是 .NET 问题。我在 GitHub 上提出了这个问题,因为所有证据都指向 .NET Core 2.1 之后的 HttpClientHandler 中断。Stephen 能够向我指出,在 .NET Core 2.1 之前,Connection: Keep-AliveHttpClient 中默认设置了一个标头。

我一直在测试的罪魁祸首 URL 似乎需要以下其中一项才能起作用:

  • 一个Connection: Keep-Alive标题
  • Accept: */*标头,或者更具体的请求内容
  • 使用 HTTP/2 协议发送的请求。

作为参考,要应用 Header 修复之一,使用httpClient.DefaultRequestHeaders.Add(string, string),并设置 HTTP 协议,使用httpClient.DefaultRequestVersion = HttpVersion.Version20;

事实证明,这个问题不是 C# 的直接问题,而是在 .NET Core 2.1 之后发送的默认标头发生了更改。如果禁用所有标头(包括 Postman 令牌标头),我发现该问题可以在 Postman 上重现。


推荐阅读