【问题标题】:PushStreamContent isn't sending the final zero-length chunk to signal the end of streamPushStreamContent 没有发送最终的零长度块来表示流的结束
【发布时间】:2016-05-19 23:23:47
【问题描述】:

我需要使用 Odata 协议通过 WebAPI 批量导出内容。我们正在尝试使用 PushStreamContent 将结果直接从数据库中流出。当我在本地 IIS 实例中运行该服务时,它运行良好,但是当我将它推送到服务器时,它会在最后 2 KB 上流式传输数据和暂停和“挂起”。

我通过跟踪文件大小验证了这一点。在本地运行时,我将得到一个 9094KB 的文件,当我将相同的代码部署到服务器时,我得到 9092KB,然后连接保持打开状态并停止传输。如果我杀死客户端并查看文件,我将看到流的 json 在写入过程中被切断。此外,我可以查看 IIS 中打开的连接,发现该连接仍然处于活动状态。

无论如何,为什么 PushStreamContent 似乎只是停止发送数据而不关闭流?如果发生错误,则流和连接将关闭。

public HttpResponseMessage GetBulkExport(ODataQueryOptions<vwBulkExport> options)
{

    var reportData = options.ApplyTo(dbContext.vwBulkExport, new ODataQuerySettings() { EnsureStableOrdering = false });

    return new ResponseStreamer(Request).StreamAsync(reportData);

}



public class ResponseStreamer
{

    private HttpRequestMessage request;

    public ResponseStreamer(HttpRequestMessage request)
    {
        this.request = request;
    }

    public HttpResponseMessage StreamAsync(IQueryable data)
    {
        HttpResponseMessage response = request.CreateResponse();
        response.Content = new PushStreamContent(
          async (outputStream, httpContent, transportContext) =>
         {
             try
             {
                 int counter = 0;
                 foreach (var item in data)
                 {
                     counter++;

                     string json = JsonConvert.SerializeObject(item);
                     var buffer = Encoding.UTF8.GetBytes(json);
                     await outputStream.WriteAsync(buffer, 0, buffer.Length);

                     if (counter == 10)
                     {
                         counter = 0;
                         await outputStream.FlushAsync();
                     }
                 }
             }
             finally
             {

                 await outputStream.FlushAsync();
                 outputStream.Close();
                 outputStream.Dispose();
             }
         });


        return response;
    }

}

这是我的客户端代码

    using (var writer = File.OpenWrite("C:\\temp\\" + Guid.NewGuid().ToString()))
    {
        var client = new RestClient("http://localhost");
        var url =  "/odata/BulkExport";
        var request = new RestRequest(url);
        request.AddHeader("authorization", string.Format("Bearer {0}", authToken));

        request.ResponseWriter = (responseStream) => responseStream.CopyTo(writer);
        var response = client.DownloadData(request);
    }

更新

我一直在做广泛的测试,我认为正在发生的是流永远不会关闭(因此最后一个块永远不会发送过来)我通过将上面的数据迭代更改为这个得出了这个结论:

for (int count = 0; count < 1000; count++) //foreach (var item in data)
{

    string json = JsonConvert.SerializeObject(count.ToString()) + Environment.NewLine;
    var buffer = Encoding.Default.GetBytes(json);
    await outputStream.WriteAsync(buffer, 0, buffer.Length);
}

我看到的情况是它只会返回 600 个“行”。似乎又缺少 2 KB。然后我将循环更改为count &lt;601 并传输了整个流,但流永远不会关闭。我认为正在发生的是内部缓冲区大小,如果在 4K 左右(这是打印出来的数字 0-600),并且由于流没有关闭,因此永远不会收到最后几个字节。这有意义吗?

无论如何,为什么流不关闭?我在 finally 中有它,我没有看到任何错误。

更新

我发现了更多信息。 HTTP 1.1 规范说分块流需要以零长度块结束。经过一番挖掘,我发现它应该发生,但无论出于何种原因,它都没有。在我的客户端中,我删除了 Connection: Keep-Alive 标头并将其替换为 Connection: Close 我有同样的问题,但是一旦我强制关闭连接(通过关闭我的测试应用程序)最后几个字节写入磁盘,一切都很好。这就是我知道零长度块没有被发送的方式。

所以现在问题变成了。 为什么当我关闭流时没有发送最终的零长度块?根据我的阅读,调用 HttpContext.Current.ApplicationInstance.CompleteRequest(); 应该会强制请求结束并写出该块。我将其添加为 finally 块中的最后一行,并使用我知道它正在运行的调试器。但是,该块仍未设置。

请记住,所有这些都可以在我托管在 IIS 中的开发机器上运行,但不能在 Web 服务器上运行。

我的机器运行的是 Windows 10,我安装了 asp.net 5,以及所有默认设置的 IIS7。

Web 服务器是 Windows Server(我不确定版本)运行 IIS8 但它只安装了 asp.net 4.5。 我最初的预感是这是问题所在 - 不同版本的asp.net 框架,但我检查了该项目仅针对 ASP.NET 4.5。我仍然会尝试更新服务器,但由于我的目标是 4.5,我认为它不会有任何好处。

【问题讨论】:

    标签: asp.net asp.net-mvc odata asp.net-web-api2 pushstreamcontent


    【解决方案1】:

    我认为问题出在 .net 框架中。将服务器更新到 .net 4.6 后,它正在工作。

    这是我应用的补丁。 https://www.microsoft.com/en-us/download/details.aspx?id=48137

    【讨论】:

    • 我想在广告中说明我不必以 4.6 为目标;只需安装它即可解决问题。考虑到 4.6 是 4.6 的替代品,这是有道理的
    猜你喜欢
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    • 2020-07-30
    • 1970-01-01
    • 2018-05-18
    • 1970-01-01
    • 2019-11-08
    • 1970-01-01
    相关资源
    最近更新 更多