[英]Stream on the fly zipped files to client via rest endpoint
I am trying to stream on the fly zipped files but memory consumption is high.我正在尝试 stream 即时压缩文件,但 memory 消耗量很高。 For example, to zip total file size of 2.8 GB is taking nearly 5 GB of processor memory.
例如,对于 zip,2.8 GB 的总文件大小占用了近 5 GB 的处理器 memory。
[Route("zip")]
public class ZipController : ControllerBase
{
private readonly HttpClient _httpClient;
public ZipController()
{
_httpClient = new HttpClient();
}
[HttpPost]
public async Task Zip([FromBody] JsonToZipInput input)
{
Response.ContentType = "application/octet-stream";
Response.Headers.Add($"Content-Disposition", $"attachment; filename=\"{input.FileName}\"");
using var zipArchive =
new ZipArchive(Response.BodyWriter.AsStream(), ZipArchiveMode.Create);
foreach (var (key, value) in input.FilePathsToUrls)
{
var zipEntry = zipArchive.CreateEntry(key, CompressionLevel.Optimal);
await using var zipStream = zipEntry.Open();
await using var stream = await _httpClient.GetStreamAsync(value);
await stream.CopyToAsync(zipStream);
}
}
}
I believe you should be able to call Response.StartAsync
:我相信您应该可以调用
Response.StartAsync
:
[HttpPost]
public async Task Zip([FromBody] JsonToZipInput input)
{
Response.ContentType = "application/octet-stream";
Response.Headers.Add($"Content-Disposition", $"attachment; filename=\"{input.FileName}\"");
await Response.StartAsync();
using var zipArchive = new ZipArchive(Response.BodyWriter.AsStream(), ZipArchiveMode.Create);
foreach (var (key, value) in input.FilePathsToUrls)
{
var zipEntry = zipArchive.CreateEntry(key, CompressionLevel.Optimal);
await using var zipStream = zipEntry.Open();
await using var stream = await _httpClient.GetStreamAsync(value);
await stream.CopyToAsync(zipStream);
}
}
StartAsync
should start the response being sent. StartAsync
应该开始发送响应。 Note that neither the response headers nor the status code can be modified once StartAsync
is called.请注意,一旦调用
StartAsync
,就不能修改响应标头和状态代码。
In particular, this means that your exception handling will be different.特别是,这意味着您的异常处理将有所不同。 Previously, an exception (eg, from a bad URL in the request) would cause an exceptional status code (ie, 500).
以前,异常(例如,来自请求中的错误 URL)会导致异常状态代码(即 500)。 With a streaming response, any exceptions after
StartAsync
cannot change the status code;使用流式响应,
StartAsync
之后的任何异常都无法更改状态码; it's already been sent.它已经发送了。 Instead, it will appear to the client as though the connection was terminated without a clean close.
相反,它会在客户端看来好像连接在没有完全关闭的情况下终止。 Complicating this a bit further, this behavior is not uncommon for web servers to do in the successful case, so clients may not complain - they would just end up with truncated (invalid) zip files.
使这进一步复杂化的是,web 服务器在成功的情况下执行此行为并不少见,因此客户端可能不会抱怨 - 他们最终会得到截断(无效)的 zip 文件。 (In the case of streaming zips, the "file table" in the zip is sent last instead of first).
(在流式 zip 的情况下,zip 中的“文件表”最后发送而不是第一个发送)。
So, this should work, but I also recommend:所以,这应该可行,但我也建议:
StartAsync
.StartAsync
之后的异常。 There is no way to return error details to the client, so you must rely on logging.
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.