块压缩响应与NancyFX自托管

本文关键字:NancyFX 压缩 响应 | 更新日期: 2023-09-27 18:18:15

我有一个应该将行写入HTTP响应流的系统。该系统中的每一行都表示某种事件,因此您可以将其视为通知流。我在Windows 7上使用。net 4,使用NancyFX和Nancy self hosting(0.23)。下面的代码是功能性的:

using System;
using System.IO;
using System.Threading;
using Nancy;
using Nancy.Hosting.Self;
namespace TestNancy
{
    public class ChunkedResponse : Response
    {
        public ChunkedResponse()
        {
            ContentType = "text/html; charset=utf-8";
            Contents = stream =>
            {
                using (var streamWriter = new StreamWriter(stream))
                {
                    while (true)
                    {
                        streamWriter.WriteLine("Hello");
                        streamWriter.Flush();
                        Thread.Sleep(1000);
                    }
                }
            };
        }
    }
    public class HomeModule : NancyModule
    {
        public HomeModule()
        {
            Get["/"] = args => new ChunkedResponse();
        }
    }
    public class Program
    {
        public static void Main()
        {
            using (var host = new NancyHost(new Uri("http://localhost:1234")))
            {
                host.Start();
                Console.ReadLine();
            }
        }
    }
}

现在我想对流添加压缩以压缩带宽。由于某种原因,在浏览器中测试时,我看不到任何结果。我已经尝试了很多组合来达到预期的结果,但这是我目前所拥有的:

using System; using System.IO; using System.IO.Compression; using System.Threading; using Nancy; using Nancy.Hosting.Self;
namespace TestNancy {
    public class ChunkedResponse : Response
    {
        public ChunkedResponse()
        {
            Headers["Content-Encoding"] = "gzip";
            ContentType = "text/html; charset=utf-8";
            Contents = stream =>
            {
                using (var gzip = new GZipStream(stream, CompressionMode.Compress))
                using (var streamWriter = new StreamWriter(gzip))
                {
                    while (true)
                    {
                        streamWriter.WriteLine("Hello");
                        streamWriter.Flush();
                        Thread.Sleep(1000);
                    }
                }
            };
        }
    }
    public class HomeModule : NancyModule
    {
        public HomeModule()
        {
            Get["/"] = args => new ChunkedResponse();
        }
    }
    public class Program
    {
        public static void Main()
        {
            using (var host = new NancyHost(new Uri("http://localhost:1234")))
            {
                host.Start();
                Console.ReadLine();
            }
        }
    } }

我正在寻找帮助,要么告诉我我做错了什么关于HTTP协议(例如,我尝试添加块长度如HTTP1.1所述,没有工作),或帮助有关南希,它做的事情我没有说明。

块压缩响应与NancyFX自托管

问题似乎是在Gzip框架的实现中,因为它在关闭之前从未写入输出流,

我只是使用SharpZiplib和你的代码似乎为我工作,这是我的修改

public class ChunkedResponse : Response
{
    public ChunkedResponse()
    {
        Headers["Transfer-Encoding"] = "chunked";
        Headers["Content-Encoding"] = "gzip";
        ContentType = "text/html; charset=utf-8";
        Contents = stream =>
        {
            var gzip = new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(stream);
            using (var streamWriter = new StreamWriter(gzip))
            {
                while (true)
                {
                    streamWriter.WriteLine("Hello");
                    gzip.Flush();
                    streamWriter.Flush();
                    Thread.Sleep(1000);
                }
            }
        };
    }
}

public class HomeModule : NancyModule
{
    public HomeModule()
    {
        Get["/"] = args => new ChunkedResponse();
    }
}
public class Program
{
    public static void Main()
    {
        using (var host = new NancyHost(new HostConfiguration{AllowChunkedEncoding = true},new Uri("http://localhost:1234")))
        {
            host.Start();
            Console.ReadLine();
        }
    }
}

SharpZipLib的Nuget包:PM> Install-Package SharpZipLib

看起来好像无论什么调用您作为ChunkedReponse.Contents提供的委托将永远不会返回,因为while(true)。这是有意的行为吗?因为不知道这个框架对那个委托做了什么,所以我猜不出来。

乍一看,我确实想知道构造函数是否永远不会返回-我猜这肯定会导致问题-但我很快就注意到它是一个lambda。幸运的是。

编辑# 1:

GZipStream.Flush()的文档说:

此方法的当前实现没有功能。(覆盖Stream.Flush()。)

这个对我来说意味着GZipStream在关闭之前不会向传输写入任何内容。如果您不永远运行上述委托,而是在某个时候关闭流,您是否会体验到不同的行为?

我已经自己测试过了,我认为问题是浏览器如何处理这些块和压缩的响应。这是我尝试过的,基本上是有效的:

Contents = stream =>
        {
            using (var gzip = new GZipStream(stream, CompressionMode.Compress))
            using (var streamWriter = new StreamWriter(gzip))
            {
                for (int i = 0; i < 5;i++ )
                {
                    string txt = "Hello";
                    streamWriter.WriteLine(txt);
                    streamWriter.Flush();
                    Thread.Sleep(1000);
                }
            }
        };

问题是浏览器在显示结果之前要等待分块响应准备好。虽然gzip支持流,但它可能会在解压缩时等待所有数据发送完毕。下面是支持我的假设的第一个提示。