简体   繁体   English

在内容 100% 完成之前从 HttpResponseMessage 读取标头

[英]Read headers from HttpResponseMessage before Content is 100% complete

  1. How do I access the response headers, before the entire response has been streamed back?在整个响应流回之前,如何访问响应标头?
  2. How do I read the stream as it arrives?我如何在流到达时读取它?
  3. Is HttpClient my best choice for such granular control of receiving the http response? HttpClient 是我对接收 http 响应进行这种精细控制的最佳选择吗?

Here's a snip that might illustrate my question:这是一个可能说明我的问题的片段:

using (var response = await _httpClient.SendAsync(request,
  HttpCompletionOption.ResponseHeadersRead))
{
   var streamTask = response.Content.ReadAsStreamAsync();
   //how do I check if headers portion has completed? 
   //Does HttpCompletionOption.ResponseHeadersRead guarantee that?
   //pseudocode
   while (!(all headers have been received)) 
     //maybe await a Delay here to let Headers get fully populated
   access_headers_without_causing_entire_response_to_be_received

   //how do I access the response, without causing an await until contents downloaded?
   //pseudocode
   while (stremTask.Resul.?) //i.e. while something is still streaming
     //? what goes here? a chunk-read into a buffer? or line-by-line since it's http?
   ...


Edit to clarify another gray area for me:编辑为我澄清另一个灰色区域:
Any reference I unearthed has some kind of a blocking statement, that would cause await for the contents to arrive. 我发现的任何参考都有某种阻塞语句,这会导致等待内容到达。 References I read usually access methods or properties on the streamTask.Result or on the Content, and I don't know enough to rule out which such references are okay as the streamTask is progressing vs. which are going to cause an await until the task completes.我阅读的引用通常访问 streamTask.Result 或 Content 上的方法或属性,并且我不知道足以排除哪些此类引用是可以的,因为 streamTask 正在进行与哪些将导致等待直到任务完成。

Based on my own testing, the content won't be transferred until you start reading the content stream, and you're correct that calling Task.Result is a blocking call, but its very nature, it's a synchronisation point.根据我自己的测试,在您开始阅读内容流之前不会传输内容,并且您正确地认为调用Task.Result是一个阻塞调用,但它的本质是一个同步点。 But , it doesn't block to pre-buffer the entire content, it only blocks until the content starts to come from the server.但是,它不会阻止对整个内容进行预缓冲,它只会阻止内容开始来自服务器。

So an infinite stream won't block for an infinite amount of time.所以无限流不会阻塞无限长的时间。 As such, trying to fetch the stream asynchronously might be deemed overkill, especially if your header processing operation is relatively short.因此,尝试异步获取流可能被认为是矫枉过正,尤其是在您的标头处理操作相对较短的情况下。 But if you want to, you can always process the headers while the content stream is being handled on another task.但是,如果您愿意,您始终可以在处理另一项任务的内容流时处理标头。 Something like this would accomplish that.像这样的事情将实现这一点。

static void Main(string[] args)
{
    var url = "http://somesite.com/bigdownloadfile.zip";
    var client = new HttpClient();
    var request = new HttpRequestMessage(HttpMethod.Get, url);

    var getTask = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
    Task contentDownloadTask = null;

    var continuation = getTask.ContinueWith((t) =>
    {
        contentDownloadTask = Task.Run(() =>
        {
            var resultStream = t.Result.Content.ReadAsStreamAsync().Result;
            resultStream.CopyTo(File.Create("output.dat"));
        });

        Console.WriteLine("Got {0} headers", t.Result.Headers.Count());
        Console.WriteLine("Blocking after fetching headers, press any key to continue...");
        Console.ReadKey(true);
    });

    continuation.Wait();
    contentDownloadTask.Wait();
    Console.WriteLine("Finished downloading {0} bytes", new FileInfo("output.dat").Length);

    Console.WriteLine("Finished, press any key to exit");
    Console.ReadKey(true);
}

Note that there's no need to check if the headers portion is complete, you've explicitly specified that with the HttpCompletionOption.ResponseHeadersRead option.请注意,无需检查标头部分是否完整,您已经使用HttpCompletionOption.ResponseHeadersRead选项明确指定了这一点。 The SendAsync task will not continue until the headers have been retrieved. SendAsync任务在检索到标头之前不会继续。

The result using the await/async keywords it's even more readable:使用 await/async 关键字的结果更具可读性:

var url = "http://somesite.com/bigdownloadfile.zip";

using (var httpClient = new HttpClient())
using (var httpRequest = new HttpRequestMessage(HttpMethod.Get, url ))
using(HttpResponseMessage response = await httpClient.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead))
using (Stream stream = await response.Content.ReadAsStreamAsync())
{
    //Access to the Stream object as it comes, buffer it or do whatever you need
}    

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM