带有请求标头“范围”的 .NET HttpClient 不起作用

Posted

技术标签:

【中文标题】带有请求标头“范围”的 .NET HttpClient 不起作用【英文标题】:.NET HttpClient with request header "Range" is not working 【发布时间】:2021-12-12 18:05:55 【问题描述】:

使用这个curl 命令:

> curl --range 0-999 -I https://us.download.nvidia.com/Windows/497.09/497.09-desktop-win10-win11-64bit-international-dch-whql.exe

响应正确返回为:

HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Cache-Control: max-age=86400
Content-Range: bytes 0-999/870849168
Content-Type: application/octet-stream
Date: Sun, 12 Dec 2021 17:38:31 GMT
Etag: "1774295931"
Last-Modified: Wed, 01 Dec 2021 12:42:07 GMT
Content-Length: 1000

当使用 .NET HttpClient 时,它似乎因范围请求标头而失败:

var url = "https://us.download.nvidia.com/Windows/497.09/497.09-desktop-win10-win11-64bit-international-dch-whql.exe";

var req = new HttpRequestMessage();
req.Method = HttpMethod.Get;
req.RequestUri = new Uri(url);
// req.Headers.Range = new RangeHeaderValue(0, 999);  // not working
req.Headers.Add("Range", "bytes=0-999");  // not working
WriteLine(req.ToString() );

var client2 = new HttpClient();
var respTask2 = client2.SendAsync(req, HttpCompletionOption.ResponseHeadersRead);
var resp2 = respTask2.GetAwaiter().GetResult();
WriteLine(resp.ToString() );

HttpClient 响应返回为:

Method: GET, RequestUri: 'https://us.download.nvidia.com/Windows/497.09/497.09-desktop-win10-win11-64bit-international-dch-whql.exe', Version: 1.1, Content: <null>, Headers:

  Range: bytes=0-999

StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:

  Accept-Ranges: bytes
  Date: Sun, 12 Dec 2021 17:44:07 GMT
  ETag: "1774295931"
  Content-Type: application/octet-stream
  Last-Modified: Wed, 01 Dec 2021 12:42:07 GMT
  Content-Length: 870849168

如何将Range 标头与HttpClient 请求一起使用?我想知道这是一个错误还是什么?

参考:HttpRequestHeaders.Range Property

【问题讨论】:

req.Headers.Add("Range", "bytes"); 效果更好吗? @LajosArpad 那么我将如何指定范围数字呢? 您的代码无法编译,一旦修复,就不会产生您发布的响应。它实际上返回Content-Length: 1000。看起来您混合了多个请求和响应并打印了错误的响应。不要急于假设每个 .NET Core 开发人员使用的东西都坏了。创建一个新的空项目并添加重现错误所需的minimal 代码。如果不能,则问题出在您的其余代码中 PS:不要使用GetAwaiter().GetResult()。请改用async/await。您可以在 Main 方法中使用 async Task Main(string[] args),因此很少有任何理由阻止 @PanagiotisKanavos 当控制台应用程序的Main 变为async 时,它只是在到达await 行时返回到控制台提示符。我只是不喜欢这种行为,因为它似乎超出了我的控制范围,所以来了好老的GetAwaiter 【参考方案1】:

RangeHeaderValue 似乎在 net5.0 下按预期工作:

var url = "https://us.download.nvidia.com/Windows/497.09/497.09-desktop-win10-win11-64bit-international-dch-whql.exe";
var client = new HttpClient();
var req = new HttpRequestMessage  RequestUri = new Uri( url ) ;
req.Headers.Range = new RangeHeaderValue( 0, 999 );

var resp = await client.SendAsync( req );

Console.WriteLine( $"\r\nResponse:\r\nresp" );

使用响应输出:

StatusCode: 206, ReasonPhrase: 'Partial Content', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:

  Accept-Ranges: bytes
  Age: 18147
  Cache-Control: max-age=86400
  Date: Sun, 12 Dec 2021 18:25:42 GMT
  ETag: "1774295931"
  Server: ECAcc
  Server: (daa/7CFD)
  X-Cache: HIT
  x-vdms-version: 117
  Content-Range: bytes 0-999/870849168
  Content-Type: application/octet-stream
  Expires: Mon, 13 Dec 2021 18:25:42 GMT
  Last-Modified: Wed, 01 Dec 2021 12:42:07 GMT
  Content-Length: 1000

在进一步检查您发布的代码后:

var resp2 = respTask2.GetAwaiter().GetResult();
WriteLine(resp.ToString() );

注意WriteLineresp.ToString(),但应该使用resp2.ToString()。所以,看起来你实际上是在打印一些其他的响应。

【讨论】:

以上是关于带有请求标头“范围”的 .NET HttpClient 不起作用的主要内容,如果未能解决你的问题,请参考以下文章

如何发送带有标头参数的 HTTP 请求?

使用flash发送带有自定义标头的POST请求

带有发布请求的 Angular 6 标头不起作用

带有授权标头的 Websocket 连接

预检成功,但取消了带有授权标头的响应

带有 PHP 标头的跨域请求标头 (CORS)