gpt4 book ai didi

asp.net - PushStreamContent 不会发送最终的零长度 block 来表示流结束

转载 作者:行者123 更新时间:2023-12-02 16:45:49 24 4
gpt4 key购买 nike

我需要使用 Odata 协议(protocol)通过 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);
}

更新

我已经进行了广泛的测试,我认为正在发生的事情是流永远不会关闭(因此最后一个 block 永远不会被发送)我通过将上面的数据迭代更改为这样得出了这个结论:

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 <601整个流都被传输,但流永远不会关闭。我认为发生的情况是内部缓冲区大小约为 4K(这就是打印出来的数字 0-600),并且由于流没有关闭,因此永远不会收到最后几个字节。这有道理吗?

无论如何,为什么流不会关闭?我把它放在最后,我没有看到任何抛出的错误。

更新

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

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

请记住,所有这些都适用于托管在 IIS 中的我的开发计算机,但不适用于 Web 服务器。

我的计算机运行的是 Windows 10,安装了 asp.net 5,并且使用所有默认设置的 IIS7。

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

最佳答案

我认为该问题是由于 .net 框架中的错误造成的。将服务器更新到 .net 4.6 后,它就可以工作了。

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

关于asp.net - PushStreamContent 不会发送最终的零长度 block 来表示流结束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35301141/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com