【问题标题】:C# MVC Download Big File from S3 AsyncC# MVC 从 S3 异步下载大文件
【发布时间】:2019-07-03 11:14:58
【问题描述】:

我必须从 aws S3 async 下载文件。我有一个锚标签,单击它时,控制器中将点击一个方法以供下载。该文件应该在浏览器底部开始下载,就像其他文件下载一样。

在视图中

<a href="/controller/action?parameter">Click here</a>

在控制器中

public void action()
{
     try
     {
           AmazonS3Client client = new AmazonS3Client(accessKeyID, secretAccessKey);
           GetObjectRequest req = new GetObjectRequest();
           req.Key = originalName;
           req.BucketName = ConfigurationManager.AppSettings["bucketName"].ToString() + DownloadPath;
           FileInfo fi = new FileInfo(originalName);
           string ext = fi.Extension.ToLower();
           string mimeType = ReturnmimeType(ext);
           var res = client.GetObject(req);
           Stream responseStream = res.ResponseStream;
           Stream response = responseStream;
           return File(response, mimeType, downLoadName);
     }
     catch (Exception)
     {
           failure = "File download failed. Please try after some time.";   
     }              
}

上述功能使浏览器加载,直到文件完全下载。然后只有文件在底部可见。我看不到 mb 的下载方式。
提前致谢。

【问题讨论】:

  • 尝试在return 之前添加Response.BufferOutput = false;。这将禁用文件的服务器端缓冲。

标签: c# asp.net-mvc amazon-s3


【解决方案1】:

您必须向客户端发送ContentLength 才能显示进度。浏览器没有关于它将接收多少数据的信息。

如果您查看File 方法使用的FileStreamResult 类的源代码,它不会通知客户端有关“Content-Length”的信息。 https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/FileStreamResult.cs

替换这个,

return File(response, mimeType, downLoadName);

return new FileStreamResultEx(response, res.ContentLength, mimeType, downloadName);


public class FileStreamResultEx : ActionResult{

     public FileStreamResultEx(
        Stream stream, 
        long contentLength,         
        string mimeType,
        string fileName){
        this.stream = stream;
        this.mimeType = mimeType;
        this.fileName = fileName;
        this.contentLength = contentLength;
     }


     public override void ExecuteResult(
         ControllerContext context)
     {
         var response = context.HttpContext.Response; 
         response.BufferOutput = false;
         response.Headers.Add("Content-Type", mimeType);
         response.Headers.Add("Content-Length", contentLength.ToString());
         response.Headers.Add("Content-Disposition","attachment; filename=" + fileName);

         using(stream) { 
             stream.CopyTo(response.OutputStream);
         }
     }

}

替代方案

通常,从您的服务器下载和交付 S3 文件是一种不好的做法。您的主机帐户将被收取两倍的带宽费用。相反,您可以使用签名 URL 来交付非公共 S3 对象,只需几秒钟的时间。您可以简单地使用 Pre-Signed-URL

 public ActionResult Action(){
     try{
         using(AmazonS3Client client = 
              new AmazonS3Client(accessKeyID, secretAccessKey)){
            var bucketName = 
                 ConfigurationManager.AppSettings["bucketName"]
                .ToString() + DownloadPath;
            GetPreSignedUrlRequest request1 = 
               new GetPreSignedUrlRequest(){
                  BucketName = bucketName,
                  Key = originalName,
                  Expires = DateTime.Now.AddMinutes(5)
               };

            string url = client.GetPreSignedURL(request1);
            return Redirect(url);
         }
     }
     catch (Exception)
     {
         failure = "File download failed. Please try after some time.";   
     }              
 }

只要对象没有公共读取策略,用户未经签名就无法访问对象。

此外,您必须在AmazonS3Client 周围使用using,以便快速释放网络资源,或者只使用AmazonS3Client 的一个静态实例,以减少不必要的分配和释放。

【讨论】:

  • 嘿 - 不错的答案,我 +1。然而,关于“PreSignedURL”——我得承认我真的不喜欢这个重定向 URL 的格式,它透露了太多信息(例如,它表明该文件来自 Amazon S3)。
  • 另外 - 你不应该将stream 包装在 using 块中吗?会自动处理吗?它会做什么?我知道 FileStreamResult 处理处置,但在这里你继承了一个不同的类......
  • @Bartosz 完成,流现在被包装,这种方法的问题是,它不是很有效,因为它不处理范围处理,电子标签匹配等,所以每次浏览器请求文件,即使没有更改,您最终也会发送整个文件。预签名 URL 负责处理它,它支持 HTTP 流(iOS 用于视频获取,它使用范围处理)、电子标签支持、if-modified 标头等。另一个更长的方法是在本地硬盘缓存中下载文件并让IIS发送文件,通过发送File( filePath, contentType )方法,IIS支持http流。
【解决方案2】:

据我了解,您想从您的服务器到 S3 进行“反向代理”之类的操作。非常有用的文章如何使用 Nginx 做到这一点,你可以在这里找到:https://stackoverflow.com/a/44749584

【讨论】:

    猜你喜欢
    • 2015-08-27
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    • 2021-07-19
    相关资源
    最近更新 更多