我正在使用Nancy编写一个简单的Web应用程序。至少有一个请求会导致一个未知长度的流,所以我不能提供Content-Llong
。我想使用Transtrans-Encode: chunked
,或者(在这种情况下同样可以接受,Connection:close
)。
我对Nancy源代码进行了快速破解,并添加了Response. BufferOutput
,以及将HttpContext.Response.BufferOutput
设置为false
的代码。你可以在这里看到:
public class HomeModule : NancyModule
{
public HomeModule()
{
Get["/slow"] = _ => new SlowStreamResponse();
}
private class SlowStreamResponse : Response
{
public SlowStreamResponse()
{
ContentType = "text/plain";
BufferOutput = false;
Contents = s => {
byte[] bytes = Encoding.UTF8.GetBytes("Hello World\n");
for (int i = 0; i < 10; ++i)
{
s.Write(bytes, 0, bytes.Length);
Thread.Sleep(500);
}
};
}
}
它似乎没有任何效果。响应在5秒后立即出现。我已经在一个简单的基于WebRequest
的客户端上测试了这个。
我如何让分块输出在南希工作?我正在使用ASP.NET托管,但我对其他托管选项的答案感兴趣。
如果我使用HttpListener
编写一个简单的服务器,我可以将SendChanked
设置为true
,它会发送分块输出,我的简单客户端会正确接收分块。
在我的实验中,我发现我需要以下配置。首先,按照Nancy Wiki中的文档设置您的web. config
文件。值得注意的是,为了设置disableoutputbuffer
值(这是我们想要的),您目前似乎还需要指定一个引导程序。在程序集中创建一个继承自的类Nancy.HostingAspnet.DefaultNancyAspNetBootstrapper
并在配置文件中指定它似乎可以工作。
<configSections>
<section name="nancyFx" type="Nancy.Hosting.Aspnet.NancyFxSection" />
</configSections>
<nancyFx>
<bootstrapper assembly="YourAssembly" type="YourBootstrapper"/>
<disableoutputbuffer value="true" />
</nancyFx>
之后,您不应该设置Transtrans-Encode
标头。相反,以下路由定义显示正确地将结果从我的IISExpress开发服务器流式传输到Chrome:
Get["/chunked"] = _ =>
{
var response = new Response();
response.ContentType = "text/plain";
response.Contents = s =>
{
byte[] bytes = System.Text.Encoding.UTF8.GetBytes("Hello World ");
for (int i = 0; i < 10; ++i)
{
for (var j = 0; j < 86; j++)
{
s.Write(bytes, 0, bytes.Length);
}
s.WriteByte(10);
s.Flush();
System.Threading.Thread.Sleep(500);
}
};
return response;
};
由于在其他StackOverflow问题中记录的首次渲染之前的最小大小,我为每个块指定了比上一个示例更多的内容
你必须在每个Write()
之后调用Flush()
,否则响应无论如何都会被缓冲。此外,谷歌Chrome在全部接收到输出之前不会呈现输出。
我通过编写一个简单的客户端应用程序发现了这一点,该应用程序记录了它在响应流到达时从响应流中读取的内容。
如果使用.NET4.5,也可以使用Stream. CopyTo代替flush。
Get["/chunked"] = _ =>
{
var response = new Response();
response.ContentType = "text/plain";
response.Contents = s =>
{
using(var helloStream = new MemoryStream(Encoding.UTF8.GetBytes("Hello World ")))
helloStream.CopyTo(s);
}
return response;
}