简体   繁体   English

Stream 通过 rest 端点将文件压缩到客户端

[英]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:所以,这应该可行,但我也建议:

  1. Ensure your exception logging works for exceptions after StartAsync .确保您的异常日志记录适用于StartAsync之后的异常。 There is no way to return error details to the client, so you must rely on logging.无法将错误详细信息返回给客户端,因此您必须依赖日志记录。
  2. If you control the client, test out this new error situation, and see if you can detect it.如果您控制客户端,请测试这种新的错误情况,看看您是否可以检测到它。 If it's not detectable using that client, then ensure your code validates the zip.如果使用该客户端无法检测到,请确保您的代码验证 zip。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 将大文件发布到REST Endpoint C#.net Core - Post large files to REST Endpoint c# .net core Paypal发布到C#REST API端点 - Paypal post to C# REST API endpoint 如何处理身份验证并记住 Websocket 端点上的客户端 c# - How to handle auth and remember client on Websocket Endpoint in c# Stream CopyToAsync - 检测客户端断开连接并设置超时 - Stream CopyToAsync - Detect client disconnection and set a timeout 通过REST在DocumentDb中创建文档时未经授权 - Unauthorized when creating a document in DocumentDb via REST 令牌服务器上自定义端点的身份服务器 4 客户端凭据 - Identity Server 4 Client Credentials for custom endpoint on token Server 如何配置 IIS 以定义路由时特定端点所需的客户端证书使端点路径与物理路径不同 - How to configure IIS to define Client Certificate required on a specific endpoint when routing make endpoint path different from physical path 从包含 zip 的流中提取文件 - Extract files from stream containing zip 是否可以将 ffmpeg 命令的 output 的 output 命令发送到具有点网核心的客户端? - Is it possible to stream the output of an ffmpeg command to a client with dot net core? 使用JWT令牌从另一个API调用REST API客户端 - Call REST API Client from another API with JWT token
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM