我很难理解 GZipStream ASP.Net 核心中间件
本文关键字:Net 核心 中间件 ASP GZipStream 难理解 | 更新日期: 2023-09-27 18:36:19
我认为自己在 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 核心中间件中提取的,"令人惊讶的是",它可以工作......或者看起来是这样(我用小提琴手测试过)。
让我先说我的理解:
- 代码首先引用
responseStream
中的httpContext.Response.Body
。 - 然后
httpContext.Response.Body
引用替换为新初始化的memoryStream
。 - 如果我了解 C# 引用的工作原理,我说我们仍然有对原始
httpContext.Response.Body
数据的引用,responseStream
,而httpContext.Response.Body
新数据是空的。 - 接下来,我们将调用管道中的下一个中间件。
- 因为
this.next()
是等待的,所以我们的代码执行将"停止",直到所有中间件都返回。 - 当我们的代码执行"恢复"时,它将初始化一个
GZipStream
,添加一个响应标头,并"寻找"到memoryStream
的开头。 - 最后,它将内容或
memoryStream
复制到compressedStream
,将其写入responseStream
。
那么,memoryStream
、compressedStream
和responseStream
之间的关系是什么呢?我们创建了compressedStream
来写入responseStream
,然后最终写入httpContext.Response.Body
,但是从responseStream
到httpContext.Response.Body
的引用不再存在了?
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);
}
}
希望有帮助。
代码只是获取管道中下一个中间件写入memoryStream
对象的内容,并将其压缩,以便使用responseStream
运行此中间件之前的任何内容响应客户端。
所以现有的responseStream
内容+memoryStream
内容。