首页 文章

我无法理解GZipStream ASP.Net核心中间件

提问于
浏览
2

我认为自己在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 .

  • 然后用新初始化的 memoryStream 替换 httpContext.Response.Body 引用 .

  • 如果我对C#引用如何工作的理解,我说我们仍然使用 responseStream 引用原始 httpContext.Response.Body 数据,而 httpContext.Response.Body 新数据为空 .

  • 接下来,我们正在调用管道中的下一个中间件 .

  • 因为 this.next() 是等待的,所以我们的代码执行将"stop",直到所有中间件都返回 .

  • 当我们的代码执行"resumes"时,它将初始化 GZipStream ,将响应头和"seeks"添加到 memoryStream 的开头 .

  • 最后,它将内容或 memoryStream 复制到 compressedStream ,将其写入 responseStream .

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

2 回答

  • 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);
        }
    }
    

    希望有所帮助 .

  • 0

    代码简单地将管道中的下一个中间件写入 memoryStream 对象并压缩它,以便在此中间件运行之前用 responseStream 中的任何内容响应客户端 .

    所以现有 responseStream 内容 memoryStream 内容 .

相关问题