公开下载 Azure blob 时的友好文件名

Posted

技术标签:

【中文标题】公开下载 Azure blob 时的友好文件名【英文标题】:Friendly filename when public download Azure blob 【发布时间】:2011-10-25 01:17:33 【问题描述】:

是否可以使用 GUID(或其他任何名称)的名称保存 blob,但是当用户请求文件 URI http://me.blob.core.windows.net/mycontainer/9BB34783-8F06-466D-AC20-37A03E504E3F 时,下载会使用友好名称,例如MyText.txt?

【问题讨论】:

【参考方案1】:

现在可以通过在生成共享访问签名时设置 content-disposition 标头:

  string sasBlobToken = blob.GetSharedAccessSignature(sharedPolicy, new SharedAccessBlobHeaders()
            
                ContentDisposition = "attachment; filename=" + friendlyFileName
            );
  string downloadLink = blob.Uri + sasBlobToken;

【讨论】:

天才,正是我想要的! P L U S O N E. 正是我所需要的【参考方案2】:

使用户能够在 Windows Azure 中下载文件(blob)可以通过 4 种方式完成;

直接下载 – 将容器的访问权限设置为公共读取权限或完全公共读取权限,并将 URL 公开给最终用户。这种方法的缺点显然是安全性——当 URL 暴露时,您无法控制访问。也无法检测下载,也无法在下载之前/之后执行代码。

API 下载 – 用户必须运行 Windows 应用程序、Silverlight 等。此外 – 应用程序必须包含商店帐户名称和密钥 – 这可能会危及安全性。特别是如果您有多个客户使用同一个帐户(当然,他们仍然可以拥有自己的容器)。

代理下载 – 让用户访问您服务器上的 URL – 然后从 Azure 检索文件并将其发送给用户。这样做的好处是您可以完全控制下载,您可以在下载之前/之后执行代码,并且您不必公开任何 Azure URL 的/帐户信息。事实上,最终用户甚至不会看到文件存储在 Azure 中。 您也可以通过这种方式覆盖文件名。缺点是所有流量都通过您的服务器——因此您可能会遇到瓶颈。

直通下载(Azure 共享访问签名) - 创建一个签名并将此签名插入到将用户重定向到 Azure 的 URL 中。签名使用户能够在有限的时间段内访问文件。这很可能是您的最佳选择。它允许在下载之前执行自定义代码,它将确保您的用户的最大下载速度,并确保良好的安全性。

这是一个代码 sn-p,它将文件流式传输给用户,并覆盖文件名。

//Retrieve filenname from DB (based on fileid (Guid))
// *SNIP*
string filename = "some file name.txt"; 

//IE needs URL encoded filename. Important when there are spaces and other non-ansi chars in filename.
if (HttpContext.Current.Request.UserAgent != null &&     HttpContext.Current.Request.UserAgent.ToUpper().Contains("MSIE"))
filename = HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8).Replace("+", " ");

context.Response.Charset = "UTF-8";
//Important to set buffer to false. IIS will download entire blob before passing it on to user if this is not set to false
context.Response.Buffer = false;
context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
context.Response.AddHeader("Content-Length", "100122334"); //Set the length the file
context.Response.ContentType = "application/octet-stream";
context.Response.Flush();

//Use the Azure API to stream the blob to the user instantly.
// *SNIP*
fileBlob.DownloadToStream(context.Response.OutputStream);

查看这篇博文了解更多信息:http://blog.degree.no/2012/04/downloading-blobs-from-windows-azure/

【讨论】:

感谢您提供如此详细的回答。直通下载听起来正是我需要的。一个问题,在您的代码示例中,您设置了文件的大小,是否必须这样做,因为如果不访问该文件,我将不知道此信息。 不需要设置文件大小。我这样做是为了让用户(浏览器)看到下载进度。如果不设置,下载时浏览器会显示“unknown filesize”等。 在选项 3 中 - 首先将文件下载到 webrole 的 localresource(temp) 文件夹,然后将该 url 链接到最终用户。这可能吗?好主意?在选项 4 中,有一种方法可以对最终用户隐藏 SAS url 并让他们只保存文件。我在这里处理的所有文件都是 xmls。【参考方案3】:

自 2013 年 11 月起,现在支持 Windows Azure Blob 存储中的 content-disposition 标头。您可以在创建 Blob 时或通过共享访问签名分配标头。

我修改了我的保存文档方法以采用可选参数,即要下载的友好名称。

public void SaveDocument(Stream documentToSave, string contentType, string containerName, string url, string friendlyName = null)

    var container = GetContainer(containerName);
    container.CreateIfNotExists();
    var blob = container.GetBlockBlobReference(url);
    blob.Properties.ContentType = contentType;
    if (friendlyName != null)
      blob.Properties.ContentDisposition = "attachment; filename=" + friendlyName;
    blob.UploadFromStream(documentToSave);

更多信息: http://blog.simontimms.com/2013/12/02/content-disposition-comes-to-azure/

【讨论】:

【参考方案4】:

答案是否定的。您需要在 blob 上设置 content-disposition 标头,并且无法在 blob 存储中设置该标头。

【讨论】:

谢谢。我是这么想的,但只是想确定一下。 除了建议的其他解决方法之外,如果您总是想要相同的友好名称,您可能只需命名为 http://me.blob.core.windows.net/mycontainer/9BB34783-8F06-466D-AC20-37A03E504E3F/MyText.txt 感谢@smarx - 这是一个非常简单而优雅的解决方案【参考方案5】:

首先,您可以使用自己的自定义域作为 blob URI:http://blogs.msdn.com/b/avkashchauhan/archive/2011/03/22/using-custom-domain-name-with-windows-azure-storage-instead-of-windows-stroage-name-blob-core-windows-net.aspx

为您提供的解决方案示例...

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

StorageCredentialsAccountAndKey credentials = new StorageCredentialsAccountAndKey(ConfigurationManager.AppSettings["WindowsAzureStorageAccountName"], ConfigurationManager.AppSettings["WindowsAzureStorageAccountKey"]);
CloudStorageAccount cloudStorageAccount = new CloudStorageAccount(credentials, true);

CloudBlobContainer blobContainer = blobClient.GetContainerReference("mycontainer");

// e.g. GUID of currently logged in user
string fileName = System.Web.Security.Membership.GetUser().ProviderUserKey.ToString();

CloudBlob blob = blobContainer.GetBlobReference(fileName);

byte[] blobArray = blob.DownloadByteArray();

Response.ContentType = "text/plain";
Response.AddHeader("content-disposition", "attachment; filename=" + "MyText.txt");
Response.BinaryWrite(blobArray);
Response.End();

【讨论】:

我明白你在说什么,但这取决于我将文件下载到我的服务器,然后再将其传递给客户端。我需要客户端能够直接从 azure 服务器下载。 您需要某种基于用户 GUID 的 URL 重写。也许这个可以帮助:forums.asp.net/t/1574817.aspx/1 我在 dotnt core 3.1 和CASE 1 中使用 ABP 访问它,在这种情况下我有要下载的 url,但是当 CASE 2 我只有一个多个文件的 blob 时,它将在浏览器中下载 download.extension 作为文件名请帮助【参考方案6】:

我尝试通过代码和手动设置 ContentDisposition 属性。它对我不起作用。我调整了一些东西,它开始工作了。 这可能很奇怪,但是 resposne 中的 content-disposition 标头丢失了,直到我在 blob 上传期间向 Properties and Metadata 添加了文件名。

NuGet 包:WindowsAzure.Storage(版本=9.3.3) 存储帐户种类:StorageV2(通用 v2)

        var cloudStorageAccount = CloudStorageAccount.Parse(chatStorageConnectionString);
        var cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
        string extension = ".jpg";
        string containerName = "foobar";

        var container = cloudBlobClient.GetContainerReference(containerName);

        if(!(await container.ExistsAsync()))
        
            logger.LogError($"Unable to connect to container containerName: containerName");
            return "";
        

        var imageBlob = container.GetBlockBlobReference(Guid.NewGuid().ToString() + extension);

        // These two lines are what I'm talking about
        imageBlob.Metadata.Add("ContentDisposition", "attachment; filename=\"testfire.jpg\"");
        imageBlob.Properties.ContentDisposition = "attachment; filename=\"testfire.jpg\"";

        await imageBlob.UploadFromStreamAsync(stream);
        if(!await imageBlob.ExistsAsync())
        
            logger.LogError("Image was not uploaded succesfully.");
            return "";
        

【讨论】:

以上是关于公开下载 Azure blob 时的友好文件名的主要内容,如果未能解决你的问题,请参考以下文章

下载几个文件后 Azure Blob 文件下载失败

如何通过引用文件下载 Azure Blob?

如何从 azure blob 存储下载文件

在 MVC3 中下载 Azure Blob 文件

使用 Azure 函数从 Azure Blob 存储下载文件会返回不同的文件大小

下载后如何从 azure blob 存储中删除文件