Azure文件存储的内容类型始终为application/octet-stream。

15
我目前在使用共享访问签名(SAS)令牌构建URL时遇到了Azure文件存储的问题。文件将在浏览器中下载,但内容类型始终为application/octet-stream,而不是更改为与文件的MIME类型相匹配的类型。如果我将文件放入Azure BLOB存储并使用SAS令牌构建URL,则会发送正确的内容类型(image/jpeg)以获取我的文件。
我已经将存储帐户从V1升级到V2,认为这可能是问题所在,但它没有解决问题。
有人知道我可以尝试什么来使Azure文件存储使用带有SAS令牌的URL返回正确的内容类型吗?

那个文件的内容类型属性是什么值? - Gaurav Mantri
1
我刚刚尝试了在我的一个存储账户(文件存储)中使用一个文件进行相同的操作。该文件的内容类型被设置为“image/png”。我能够正确地查看文件,并且响应头包含正确的内容类型头值。 - Gaurav Mantri
1
我已经将我的存储账户从V1升级到V2,认为那是问题的原因,但它并没有解决问题。- 离题评论:请注意V2存储账户的成本。它们比V1账户更昂贵。 - Gaurav Mantri
@GauravMantri 您如何在不下载它的情况下确定它的内容类型?我在门户中没有看到任何标识内容类型的东西。属性显示名称、URL、上次修改时间、大小、ETag 和内容 MD5。我使用门户上传了它,并且只有通过 postman 获取它时才能确定内容类型。我的 JPG 的内容类型每次都返回为 application/octet-stream。感谢您提供的定价提示。 - David Yates
抱歉,我误解了你的问题。由于某种原因,我认为即使您正确设置了内容类型,服务仍会返回“application/octet-stream”。您需要进行单独的REST API调用到文件服务以获取文件的属性。并非所有文件的属性都作为列表操作的一部分返回。您可以使用Microsoft的存储资源管理器来查看文件的属性。 - Gaurav Mantri
当从使用SFTP的第三方(闭源)应用程序上传文件时,有什么解决方案? - Aaron Hudon
12个回答

6
到目前为止,这些是我找到的唯一解决内容类型问题的方法:
  1. 使用Microsoft Azure Storage Explorer手动修改内容类型字符串。您必须右键单击文件,然后左键单击属性才能显示对话框。
  2. 使用Microsoft的WindowsAzure.Storage Nuget软件包以编程方式修改文件。
  3. 通过自己的网站提供文件下载并禁止直接访问。
对我来说,这些都不是可接受的选择。如果用户通过门户或Microsoft Azure Storage Explore上传文件并忘记更改内容类型,则前两个选项可能会导致错误。我也不想编写Azure功能或Web作业来监视和解决此问题。
由于blob存储在通过Microsoft Azure Storage Explore或通过门户上传时不具有相同的问题,并且成本更低,并且两者都与SAS令牌配合使用,因此我们正在转向blob存储。我们确实失去了将驱动器挂载到本地计算机并使用类似Beyond Compare之类的工具进行文件比较的能力,但这是我们可以接受的缺点。
如果有人有比上述解决方案更好的解决此问题的方法,我将非常乐意支持它。但是,我认为Microsoft必须进行更改才能解决此问题。

这仍然是个令人沮丧的事实,五年后还是如此:/ - undefined

5
当我通过门户上传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中,并且内容类型会降为应用程序/八位字节流。如果内容类型正确,则计划是使用此URL + SAS令牌检索SSRS报告的图像。 SRSS对其显示的文件的内容类型/媒体类型非常特别,而应用程序/八位字节流则不会被显示。这将是一个临时解决方案,直到我们也将我们的报告迁移到云端。 - David Yates
@DavidYates 感谢您的详细解释!您能告诉我如何获取完整的url+sas吗?如果您是从门户或Azure存储资源管理器中获取的,也许可以尝试使用sdk生成url,因为默认情况下门户和资源管理器不指定内容类型。如果需要,我可以提供完整的代码片段。 - Jerry Liu
@DavidYates 我已经在我的端上使用Postman进行了测试,如果我使用SDK指定头部,响应内容类型将变为image/jpeg - Jerry Liu
事实上,我们需要这个与SAS令牌一起使用以进行SSRS报告,并且我不想编写一个程序来修复内容类型。 BLOB存储正确设置了内容类型,因此这是我们目前要走的路线。至于创建SAS令牌,您可以按照以下步骤操作:
  • 获取Azure中存储文件的URL
  • 转到Azure中的存储帐户
  • 单击“共享访问签名”选项卡
  • 设置使用的开始和结束时间
  • 单击“生成SAS连接字符串”
  • 复制SAS令牌并将其粘贴到文件URL的末尾
  • 在Postman中使用URL
- David Yates
更详细一点...我很感激这段代码,因为我可能会在其他地方使用它。我们正在尝试做的事情是从我们的DB中获取图像的部分路径,从数据库中获取存储位置、SAS令牌,并将所有这些都组合到一个存储过程中供SSRS报告使用。因此,我永远无法使用C#代码动态生成SAS令牌。因此,内容类型必须始终正确才能正常工作。 - David Yates
@DavidYates之前没有理解你的需求,很抱歉浪费了您的时间。同时非常感谢您的耐心,从您的问题中学到了很多东西。希望一切顺利! - Jerry Liu

4

看一下这个 - Microsoft SAS 示例

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

例如 - https://myaccount.file.core.chinacloudapi.cn/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


这里有使用HMAC-SHA256签名的说明:https://learn.microsoft.com/en-us/rest/api/storageservices/create-user-delegation-sas#specify-the-signature - Eneerge

3
Azure Blob如果没有提供值,则会默认为'application/octet-stream'。为了获取正确的MIME类型,我在我的Flask应用程序中做了以下操作:
@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的文件的当前mime类型。

在nodeJS中:

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

其中:

fileMimeType 是正在上传的文件类型

callback是您的回调实现

使用的方法参考:https://learn.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--


1
对于任何想要正确上传带有声明的内容类型的文件的人,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

1
这适用于使用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();

enter image description here


0

我知道我并没有回答这个问题,但我相信我的答案是适用的。我曾经遇到过同样的问题,我需要将存储帐户设置为静态网站。每当我上传一个 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]。

0

基于这个答案:Twong answer

例如,如果您正在使用.NET(C#)API从ShareFileClient(ShareFileClient class description)代理/生成SAS URL:

if (downloadClient.CanGenerateSasUri)
{
    var sasBuilder = new ShareSasBuilder(ShareFileSasPermissions.Read, DateTimeOffset.Now.AddDays(10))
        {
            ContentType = "application/pdf",
            ContentDisposition = "inline"
        };
    return downloadClient.GenerateSasUri(sasBuilder);
}

上述示例设置了10天的令牌,用于打开PDF文件,该文件将在新的浏览器选项卡中打开(特别是在Apple iOS上)。


0

我没有尝试过这个,但理想情况下,您可以使用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();

0
Java中的解决方案是在生成签名图像URL时指定内容类型:
blobServiceSasSignatureValues.setContentType("image/jpeg");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接