.net 从压缩GZipStream读取

2vuwiymt  于 2023-02-17  发布在  .NET
关注(0)|答案(1)|浏览(121)

我正在探索如何在C#中实现HTTP服务器。(在你问之前,我知道有Kestrel(没有其他不过时的东西),我想要一个小得多的应用程序。)因此,响应可能是一个无法查找且长度未知的流。对于这种情况,可以使用分块编码,而不是发送内容长度报头。
响应也可以按照客户端的指示用gzip或br压缩。这可以通过GZipStream类来实现。我几乎说了“很容易”,因为事实并非如此。每次使用GZipStream API时,我总是觉得它很混乱。我通常会遇到每个异常,直到我最终把它弄对。
看起来我只能写入(推送)到GZipStream,压缩数据将从另一端慢慢流出到指定的“基”流中。但这并不理想,因为我不能让压缩数据流到客户端。它需要被分块。也就是说,压缩数据的每一位都需要以其分块大小作为前缀。当然,GZipStream不能产生这种格式。
相反,我想从压缩的GZipStream中读取(拉),但这似乎不可能。文档说如果我尝试这样做,它会抛出一个异常。但必须有一些示例将压缩的字节转化为分块格式。
那么我怎样才能得到预期的结果呢?用这个API能实现吗?为什么我不能从压缩流中拉出来,只能推出来呢?
我并不想编写(非功能性的)示例代码,因为那样只会让人感到困惑。
PS:好吧,也许这个:

Stream responseBody = ...;
if (canCompress)
{
    responseBody = new GZipStream(responseBody, CompressionMode.Compress);   // <-- probably wrong
}
// not shown: add appropriate headers
while (true)
{
    int chunkLength = responseBody.Read(buffer);   // <-- not possible
    if (chunkLength == 0)
        break;
    response.Write($"{chunkLength:X}\r\n");
    response.Write(buffer.AsMemory()[..chunkLength]);
    response.Write("\r\n");
}
response.Write("0\r\n\r\n");
yzuktlbb

yzuktlbb1#

您对GZipStream的使用不完整。虽然您输入的responseBuffer是正确的目标缓冲区,但您必须实际将字节写入GZipStream本身。
此外,一旦完成写入,必须关闭GZipStream示例以将所有压缩字节写入目标缓冲区。这是关键的一步,因为在GZip中不存在输入流的“部分压缩”。为了正确地压缩它,必须分析整个输入。因此,这是关键的缺失环节,必须发生之前,你可以继续写回应。
最后,您需要重置输出流的位置,以便可以将其读入中间响应缓冲区。

using MemoryStream responseBody = new MemoryStream();
GZipStream gzipStream = null; // make sure to dispose after use

if (canCompress)
{
    using MemoryStream gzipStreamBuffer = new MemoryStream(bytes);
    gzipStream = new GZipStream(responseBody, CompressionMode.Compress, true);

    gzipStreamBuffer.CopyTo(gzipStream);
    gzipStream.Close(); // close the stream so that all compressed bytes are written

    responseBody.Seek(0, SeekOrigin.Begin);  // reset the response so that we can read it to the buffer
}

var buffer = new byte[20];

while (true)
{
    int chunkLength = responseBody.Read(buffer);

    if (chunkLength == 0)
        break;
        
    // write response
}

在我的测试示例中,我的bytes输入是241字节,而写入缓冲区的压缩字节总计为82字节。

相关问题