如何在运行中压缩http请求而不在内存中加载压缩缓冲区

Mui*_*ota 11 .net compression gzip c#-4.0 dotnet-httpclient

我需要将http post请求中的大量数据发送到支持gziped编码请求的服务器.

从简单开始

public async Task<string> DoPost(HttpContent content)
{
  HttpClient client = new HttpClient();
  HttpResponseMessage response = await client.PostAsync("http://myUri", content);

  response.EnsureSuccessStatusCode();
  return await response.Content.ReadAsStringAsync();
}
Run Code Online (Sandbox Code Playgroud)

我刚刚添加了预压缩

public async Task<string> DoPost(HttpContent content, bool compress)
{
  if (compress) 
    content= await CompressAsync(content);

  return await DoPost(content);
}

private static async Task<StreamContent> CompressAsync(HttpContent content)
{
  MemoryStream ms = new MemoryStream();
  using (GZipStream gzipStream = new GZipStream(ms, CompressionMode.Compress, true))
  {
    await content.CopyToAsync(gzipStream);
    await gzipStream.FlushAsync();
  }

  ms.Position = 0;
  StreamContent compressedStreamContent = new StreamContent(ms);
  compressedStreamContent.Headers.ContentType = content.Headers.ContentType;
  compressedStreamContent.Headers.Add("Content-Encoding", "gzip");

  return compressedStreamContent;
}
Run Code Online (Sandbox Code Playgroud)

它完美地工作,但压缩数据在发送请求之前完全加载到内存中.我希望能够在以流媒体方式发送期间动态压缩数据.

为此,我尝试了以下代码:

private static async Task<HttpContent> CompressAsync2(HttpContent content)
{
  PushStreamContent pushStreamContent = new PushStreamContent(async (stream, content2, transport) =>
  {
    using (GZipStream gzipStream = new GZipStream(stream, CompressionMode.Compress, true))
    {
      try
      {
        await content.CopyToAsync(gzipStream);
        await gzipStream.FlushAsync();
      }
      catch (Exception exception)
      {
        throw;
      }
    }
  });
  pushStreamContent.Headers.ContentType = content.Headers.ContentType;
  pushStreamContent.Headers.Add("Content-Encoding", "gzip");

  return pushStreamContent;
}
Run Code Online (Sandbox Code Playgroud)

但它永远不会离开CopyToAsync(gzipStream).FlushAsync永远不会被执行,也不会抛出任何异常,Fiddler也看不到任何帖子.

我的问题是:

  • 为什么CompressAsync2不起作用?
  • 如何在发送期间动态压缩并且不在内存中加载压缩缓冲区?

任何帮助将不胜感激.

Dar*_*ler 13

尝试使用WebAPIContrib中的CompressedContent类https://github.com/WebApiContrib/WebAPIContrib/blob/master/src/WebApiContrib/Content/CompressedContent.cs

public async Task<string> DoPost(HttpContent content)
{
  HttpClient client = new HttpClient();
  HttpResponseMessage response = await client.PostAsync("http://myUri", 
                                 new CompressedContent(content,"gzip"));

  response.EnsureSuccessStatusCode();
  return await response.Content.ReadAsStringAsync();
}
Run Code Online (Sandbox Code Playgroud)

PS,这只会流式传输.net 4.5上的内容..net 4版本的HttpWebRequest始终缓冲已发送的内容.

PPS为每个请求创建一个新的HttpClient不是使用HttpClient的最佳方式.执行此操作将强制为每个请求创建新的TCP连接.