【问题标题】:Azure File storage content-type is always application/octet-streamAzure 文件存储内容类型始终为 application/octet-stream
【发布时间】:2018-10-05 07:26:19
【问题描述】:

当我使用 shared access signature (SAS) Token 构建 URL 时,我目前遇到了 Azure 文件存储问题。该文件将在浏览器中下载,但内容类型始终为 application/octet-stream,而不是更改以匹配文件的 mime 类型。如果我将文件放入 Azure BLOB 存储并使用 SAS 令牌构建 URL,它会为我的文件发送正确的内容类型 (image/jpeg)。

我认为这是问题所在,已将存储帐户从 V1 升级到 V2,但没有解决。

有没有人知道我可以尝试什么来让 Azure 文件存储使用带有 SAS 令牌的 URL 返回正确的内容类型来下载文件?

【问题讨论】:

  • 该文件的内容类型属性的值是多少。
  • 我刚刚对我的一个存储帐户中的一个文件(在文件存储中)进行了同样的尝试。文件的内容类型设置为image/png。我能够正确查看文件,并且响应标头包含正确的内容类型标头值。
  • I've upgraded my storage account from V1 to V2 thinking that was the problem, but it didn't fix it. - 题外话评论:请注意 V2 存储帐户的成本。它们比 V1 帐户更昂贵。
  • @GauravMantri 不下载怎么看?我在门户中看不到任何标识内容类型的内容。属性显示名称、URL、上次修改时间、大小、etag 和 content-md5。我使用门户网站上传了它,并且只能通过邮递员获取它来确定内容类型。我的 jpg 的内容类型每次都以 application/octet-stream 的形式返回。也感谢您提供定价提示。
  • 对不起,我误解了你的问题。出于某种原因,我认为即使您正确设置了内容类型,服务也会返回application/octet-stream。您需要对文件服务进行单独的 REST API 调用以获取文件的属性。并非文件的所有属性都作为列表操作的一部分返回。您可以使用 Microsoft 的 Storage Explorer 查看文件的属性。

标签: azure azure-storage-files


【解决方案1】:

我没有尝试过,但理想情况下,您可以使用 ClientOptions 指定不同的标头。它看起来像这样:

ClientOptions options = new ClientOptions();
HttpHeader httpHeaders = new HttpHeader("Content-Type", "application/pdf");
options.setHeaders(Collections.singleton(httpHeaders));
    
blobClient = new BlobClientBuilder()
                .endpoint(<SAS-URL>)
                .blobName("hello")
                .clientOptions(options)
                .buildClient();

【讨论】:

    【解决方案2】:

    看看这个 - Microsoft SAS Examples

    如果您不想在 Azure 中更新文件的内容类型,或者更新所有现有文件的内容类型太麻烦,您可以传递所需的内容类型 w/ SAS 令牌也是如此。 rsct 参数是您指定所需内容类型的位置。

    例如- https://myaccount.file.core.windows.net/pictures/somefile.pdf?sv=2015-02-21&st=2015-07-01T08:49Z&se=2015-07-02T08:49Z&sr=c&sp=r&rscd=file;%20attachment&rsct=application%2Fpdf&sig=YWJjZGVmZw%3d%3d&sig=a39%2BYozJhGp6miujGymjRpN8tsrQfLo9Z3i8IRyIpnQ%3d

    【讨论】:

      【解决方案3】:

      我知道我没有回答这个问题,但我相信答案是适用的。我的存储帐户遇到了同样的问题,我需要将其作为静态网站。每当我将 blob 上传到容器时,默认类型是“application/octet-stream”,因此 index.html 会被下载而不是显示。

      要更改文件类型,请执行以下操作:

      # Get Storage Account for its context
      $storageAccount = Get-AzStorageAccount -ResourceGroupName <Resource Group Name> -Name <Storage Account Name>
      # Get Blobs inside container of storage account
      $blobs = Get-AzStorageBlob -Context $storageAccount.Context -Container <Container Name>
      foreach ($blob in $blobs) {
          $CloudBlockBlob = [Microsoft.Azure.Storage.Blob.CloudBlockBlob] $blob.ICloudBlob
          $CloudBlockBlob.Properties.ContentType = <Desired type as string>
          $CloudBlockBlob.SetProperties()
      }
      

      注意:对于 Azure 文件存储,您可能希望将库更改为 [Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob]

      【讨论】:

        【解决方案4】:

        对于希望使用声明的内容类型正确上传文件的任何人,v12 客户端已更改设置内容类型。可以使用file.Create的ShareFileHttpHeaders参数

        ShareFileClient file = directory.GetFileClient(fileName);          
        using FileStream stream = File.OpenRead(@"C:\Temp\Amanita_muscaria.jpg");           
        file.Create(stream.Length, new ShareFileHttpHeaders { ContentType = ContentType(fileName) });           
        file.UploadRange(new HttpRange(0, stream.Length),stream);
        

        其中ContentType(fileName) 是对文件名的评估,例如:

        if (fileName.EndsWith(".txt")) return "text/plain";
        // etc
        

        【讨论】:

          【解决方案5】:

          这适用于使用 com.microsoft.azure azure-storage 库的 java。上传到共享访问签名资源。

                  InputStream is = new FileInputStream(file);
                  CloudBlockBlob cloudBlockBlob = new CloudBlockBlob(new URI(sasUri));
                  cloudBlockBlob.getProperties().setContentType("application/pdf");
                  cloudBlockBlob.upload(is, file.length());
                  is.close();
          

          【讨论】:

            【解决方案6】:
            // here you define your file content type
            CloudBlockBlob cloudBlockBlob = container.GetBlockBlobReference(file.FileName);
                            cloudBlockBlob.Properties.ContentType = file.ContentType; //content type
            

            【讨论】:

            • 请注意,这是关于 Azure 文件存储的。我将它与 Blob 存储进行对比。我最终选择了 Blob 存储,因为它的性能确实比文件存储好,而且更便宜。
            【解决方案7】:

            如果未提供任何内容,Azure blob 将使用默认值“application/octet-stream”。为了获得正确的 mimetypes,这就是我对我的烧瓶应用程序所做的:

            @app.route('/', methods=['GET', 'POST'])
            def upload_file():
                    if request.method == 'POST':
                        f = request.files['file']
                        mime_type = f.content_type
                        print (mime_type)
                        print (type(f))
                        try:
                            blob_service.create_blob_from_stream(container, f.filename, f,
                            content_settings=ContentSettings(content_type=mime_type))
                        except Exception as e:
                            print (str(e))
                            pass
            

            mime_type 被传递给 ContentSettings 以获取上传到 azure blob 的文件的当前 mimetypes。

            在 nodeJS 中:

            blobService.createBlockBlobFromStream(container, blob, stream, streamLength, { contentSettings: { contentType: fileMimeType } }, callback)

            地点:

            fileMimeType是上传文件的类型

            callback 是你的回调实现

            参考使用的方法: https://docs.microsoft.com/en-us/javascript/api/azure-storage/azurestorage.services.blob.blobservice.blobservice?view=azure-node-latest#createblockblobfromstream-string--string--stream-readable--number--createblockblobrequestoptions--errororresult-blobresult--

            【讨论】:

              【解决方案8】:

              当我通过门户将 jpeg 文件上传到文件共享时,内容类型确实更改为 application/octet-stream。但我无法重现您的下载问题。

              我没有在我的 SAS 请求 uri 中指定内容类型,但文件只是作为 jpeg 文件下载。已经在 SDK(帐户 SAS/存储访问策略/文件本身的 SAS)或 REST API 中进行了测试,即使没有内容类型也可以工作。

              您可以尝试使用以下代码指定内容类型。

               SharedAccessFileHeaders header = new SharedAccessFileHeaders()
               {
                   ContentDisposition = "attachment",
                   ContentType = "image/jpeg"
               };
              string sasToken = file.GetSharedAccessSignature(sharedPolicy,header);
              

              【讨论】:

              • 我正在使用完整的 URL + SAS 令牌下载文件以直接访问文件。我能够将该 URL + SAS 直接粘贴到 Postman 中,并且内容类型归结为 application/octet-stream。如果内容类型正确,该计划将使用此 URL + SAS 令牌来检索 SSRS 报告的图像。 SRSS 对将显示的文件的内容类型/媒体类型非常讲究,并且不显示应用程序/八位字节流。在我们将报告也迁移到云端之前,这将是一个临时解决方案。
              • @DavidYates 感谢您的详细解释!你能告诉我你如何获得完整的 url+sas 吗?如果您从门户或 Azure 存储资源管理器获取它,也许值得一试,您可以使用 sdk 生成 url,因为默认情况下门户和资源管理器不指定内容类型。如果需要,我可以提供完整的代码sn-p。
              • @DavidYates 已经在我这边使用邮递员进行了测试,如果我使用 sdk 指定标头,则响应内容类型变为image/jpeg。
              • 问题是我们需要它来处理 SSRS 报告的 SAS 令牌,我不想编写一个程序来修复内容类型。 BLOB 存储正确设置了内容类型,这就是我们当前要走的路线。至于创建 SAS 令牌,您可以按照以下步骤操作: - 获取 Azure 中存储文件的 URL - 转到我们在 Azure 中的存储帐户 - 单击“共享访问签名”选项卡 - 设置使用的开始和结束时间- 单击“生成 SAS 连接字符串” - 复制 SAS 令牌并将其粘贴到文件 URL 的末尾 - 在邮递员中使用 URL
              • 更详细一点....我很欣赏这段代码,因为我可以在其他地方使用它。我们正在尝试做的事情是从我们的数据库中获取图像的部分路径,从数据库中获取存储位置,从数据库中获取 SAS 令牌,然后在存储过程中构建所有这些以供 SSRS 报告使用。因此,我永远无法使用 C# 代码动态生成 SAS 令牌。因此,内容类型必须始终正确才能使其正常工作。
              【解决方案9】:

              到目前为止,这些是我发现的内容类型的唯一修复:

              1. 使用 Microsoft Azure 存储资源管理器手动修改内容类型字符串。您必须右键单击文件和左键单击属性才能显示对话框。
              2. 使用 Microsoft 的 WindowsAzure.Storage Nuget 包以编程方式修改文件。
              3. 通过我自己的网站下载 Surface 文件,不允许直接访问。

              对我来说,这些都不是可接受的选择。如果用户通过门户或 Microsoft Azure Storage Explorer 上传文件并忘记更改内容类型,前两个可能会导致错误。我也不想编写 Azure Functions 或 Web 作业来监视和解决此问题。

              由于在通过 Microsoft Azure Storage Explore 或通过门户上传时,blob 存储不会遇到同样的问题,因此成本要低得多,并且都可以使用 SAS 令牌,因此我们正在转向 blob 存储。我们确实失去了将驱动器安装到本地计算机并使用 Beyond Compare 之类的工具进行文件比较的能力,但这是我们可以忍受的缺点。

              如果有人有比上述解决此问题的解决方案更好的解决方案,我会很乐意投票。但是,我认为微软必须做出改变才能解决这个问题。

              【讨论】:

                猜你喜欢
                • 2018-03-18
                • 1970-01-01
                • 2019-10-16
                • 2020-08-01
                • 2018-10-27
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-05-06
                相关资源
                最近更新 更多