【问题标题】:I have trouble understanding a GZipStream ASP.Net Core Middleware我无法理解 GZipStream ASP.Net 核心中间件
【发布时间】:2016-02-26 16:54:17
【问题描述】:

我认为自己在 C# 方面相当出色,但在理解以下代码时遇到了麻烦:

using (var memoryStream = new MemoryStream())
{
    var responseStream = httpContext.Response.Body;
    httpContext.Response.Body = memoryStream;

    await this.next(httpContext);

    using (var compressedStream = new GZipStream(responseStream, CompressionLevel.Optimal))
    {
        httpContext.Response.Headers.Add("Content-Encoding", new [] { "gzip" });
        memoryStream.Seek(0, SeekOrigin.Begin);
        await memoryStream.CopyToAsync(compressedStream);
    }
}

此代码是从压缩 HTTP 响应的 ASP.Net Core 中间件中提取的,并且“令人惊讶”,它可以工作......或者看起来是这样(我用 Fiddler 对其进行了测试)。

先说说我的理解:

  • 代码以在responseStream 中引用httpContext.Response.Body 开头。
  • 然后它将httpContext.Response.Body 引用替换为新初始化的memoryStream
  • 如果我理解 C# 引用的工作原理,我说我们仍然可以引用原始的 httpContext.Response.Body 数据和 responseStream,而 httpContext.Response.Body 的新数据是空的。
  • 接下来,我们将调用管道中的下一个中间件。
  • 因为this.next() 是可等待的,所以我们的代码执行将“停止”,直到所有中间件返回。
  • 当我们的代码执行“恢复”时,它会初始化一个GZipStream,添加一个响应头,并“寻找”到memoryStream 的开头。
  • 最后,它将内容或memoryStream 复制到compressedStream,然后将其写入responseStream

那么,memoryStreamcompressedStreamresponseStream 之间的关系是什么?我们创建了compressedStream 来写入responseStream,然后最终写入httpContext.Response.Body,但是从responseStreamhttpContext.Response.Body 的引用不再存在了吗?

【问题讨论】:

    标签: c# asp.net-core gzipstream


    【解决方案1】:

    FWIW OOB ResponseCompressionMiddleware 现在看起来有点不同。

    但在您粘贴的示例中,我将注释说明为什么 memoryStream 在复制到 compressedStream 时实际上不是空的。

    using (var memoryStream = new MemoryStream()) // Create a buffer so we can capture response content written by future middleware/controller actions
    {
        var responseStream = httpContext.Response.Body; // save a reference to the ACTUAL STREAM THAT WRITES TO THE HTTP RESPONSE WHEN WRITTEN TO.
        httpContext.Response.Body = memoryStream; // replace HttpContext.Response.Body with our buffer (memoryStream).
    
        await this.next(httpContext); // <== somewhere in here is where HttpContext.Response.Body gets written to, and since Body now points to memoryStream, really memoryStream gets written to.
    
        using (var compressedStream = new GZipStream(responseStream, CompressionLevel.Optimal)) // Here is where we wrap the ACTUAL HTTP RESPONSE STREAM with our ready-to-write-to compressedStream.
        {
            httpContext.Response.Headers.Add("Content-Encoding", new [] { "gzip" });
            memoryStream.Seek(0, SeekOrigin.Begin); // Previously, we set HttpContext.Response.Body to a memoryStream buffer, then SOMEONE in the middleware chain or controller action wrote to that Body, we can seek to the beginning of what they wrote, and copy that content to the compressedStream.
            await memoryStream.CopyToAsync(compressedStream);
        }
    }
    

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      代码只是将管道中的下一个中间件写入memoryStream 对象并压缩它,以便在这段中间件运行之前使用responseStream 中的任何内容响应客户端。

      所以存在 responseStream 内容 + memoryStream 内容。

      【讨论】:

      • 如果就这么简单;我不会问;)httpContext.Response.Body 是返回给客户的;除了分配没有任何内容的responseStream 之外,我在代码的哪一部分写了任何内容。
      • 这两个语句:var responseStream = httpContext.Response.Body;new GZipStream(responseStream, CompressionLevel.Optimal)
      • 这正是让我困惑的地方:|代码将responseStream 初始化为“指向”httpContext.Response.Body;但是,httpContext.Response.Body = memoryStream; 部分删除了该引用,现在httpContext.Response.Body 是别的东西......或者我在这里缺少的.Net 引用中有什么东西?
      • 你引用的代码只是重新分配指针,它不会改变值。
      • 这对你来说似乎是一个愚蠢的问题,你可能会想“你怎么看不到它?”您试图在没有指出我误解和困惑的部分的情况下回答这个问题。是的responseStream 包含初始的httpContext.Response.BodycompressedStream 是它的压缩版本。现在我们使用空的memoryStream(它刚刚初始化)并将其内容(空)写入compressedStream。这种理解的哪一部分是错误的,为什么?
      猜你喜欢
      • 1970-01-01
      • 2019-06-06
      • 2018-03-06
      • 1970-01-01
      • 2017-04-30
      • 2021-08-23
      • 2021-04-26
      • 2017-06-09
      • 2019-02-11
      相关资源
      最近更新 更多