【问题标题】:Upload File with brackets ([ & ]) in the name上传名称中带括号 ([ & ]) 的文件
【发布时间】:2012-11-21 03:04:07
【问题描述】:

我正在将 ClickOnce 安装从常规 Web 服务器移动到 Azure Blob 存储,并且某些文件存在问题。文件名包含 [ ]CloudBlob.UploadFile 失败并出现异常:

Microsoft.WindowsAzure.Storageclient.StorageException:
访问 Blob 存储时出错:服务器无法对请求进行身份验证。确保 Authorization 标头的值格式正确,包括签名。

该代码已经使用了一段时间,并且仅在名称中带有 [ ] 的文件上失败,所以我不认为这是“身份验证失败”。在这种特殊情况下,这是循环上传的第七个文件。我找到了this link on MSDN about valid file namesthis on stack overflow which both show problems with square brackets in URL's and reference UrlEncode。我添加了对UrlEncode 的电话,但没有帮助。该容器是通过公共访问创建的,因为我们使用它来支持客户下载我们的软件。我们一直在另一个容器中托管“测试”安装,并且访问该容器也没有权限问题。

我可以在不更改名称的情况下上传文件,然后使用 newdesic 的 Azure 存储资源管理器工具重命名文件以添加“路径”,那么我没有在做什么呢?

【问题讨论】:

  • 您使用的是什么版本的 Azure SDK?
  • 我们刚刚升级到1.8 SDK和VS2012

标签: azure azure-storage azure-blob-storage azure-sdk-.net


【解决方案1】:

我看到您使用的是 1.7 SDK。这是 SDK 的一个小编码问题,也存在于 v2.0 中。让我们看看发生了什么。

无编码

account.CreateCloudBlobClient()
       .GetContainerReference("temp")
       .GetBlobReference("abc[]def.txt")
       .UploadFile("myfile.txt");

如果您不对 blob 名称进行编码,您最终会收到对以下导致身份验证异常的 URL 的请求:

http://account.blob.core.windows.net/temp/abc[]def.txt

这是因为 SDK 在内部使用 Uri.EscapeUriString 对您的字符串进行编码,但这并未考虑方括号。

编码

那么您会期望以下方法可以解决问题:

account.CreateCloudBlobClient()
       .GetContainerReference("temp")
       .GetBlobReference(HttpUtility.UrlEncode("abc[]def.txt"))
       .UploadFile("myfile.txt");

这里的问题是你最终会得到这个网址:

http://account.blob.core.windows.net/temp/abc%255b%255ddef.txt

那么这里发生了什么?调用 HttpUtility.UrlEncode 将 abc[]def.txt 变为 abc%5B%5Ddef.txt,这是正确的。但在内部,SDK 会再次对该字符串进行编码,从而生成 abc%255b%255ddef.txt,这不是您想要的。

解决方法

应用包含方括号的编码的唯一方法是使用一个小变通方法。如果您将完整的 URL 传递给 GetBlobReference 方法,SDK 会假定您自己完成了所有编码:

var container = account.CreateCloudBlobClient().GetContainerReference("temp");
var blob = container.GetBlobReference(String.Format("{0}/{1}", 
                container.Uri, System.Web.HttpUtility.UrlEncode("abc[]def.txt")));
blob.UploadFile("myfile.txt");

这会生成正确编码的 URL:

http://account.blob.core.windows.net/temp/abc%5b%5ddef.txt

如果您使用 CloudXplorer 之类的工具,您将看到具有正确文件名的 blob:

【讨论】:

  • 好的 - 这很有意义,但对我不起作用 - 我在调用 UploadFile 之前调用了 blob.DeleteIfExists() 并且该调用现在抛出相同的异常,但即使在文件上也是如此名称中不带括号
  • OK - 我需要编码整个 URI,而不仅仅是结尾 - 代码更改为:code var container = account.CreateCloudBlobClient().GetContainerReference("temp"); var blob = container.GetBlobReference(System.Web.HttpUtility.UrlEncode(String.Format("{0}/{1}", container.Uri, "abc[]def.txt"))); blob.UploadFile("myfile.txt"); code 所以 URL 最终是这样的:http%3a%2f%2faccount.blob.core.windows.net%2ftemp%2fabc%5b%5ddef.txt
  • OK - 文件正确上传,但我无法通过“未编码”URI 引用它们,并且编码字符在文件名中(abc%5b%fddef 而不是 abc[]def)。这种行为与我在 Azure 存储资源管理器中看到的不同,其中名称显示正确。
  • 你为我节省了几个小时试图弄清楚这里发生了什么。谢谢。
【解决方案2】:

.Net 4.5 中的 Uri 类中有两个已知的中断

• '[',']' 字符不再转义

• “\”字符现在转义为 %5C

当服务器尝试验证请求的签名时,这会导致身份验证,因为规范化字符串现在在客户端和服务器上不同。

存在此问题时,客户可以使用一些解决方法。正确的解决方案将取决于您的具体应用和要求。 避免在资源名称中使用‘[‘,’]’或‘\’字符 通过简单地同时避免这些字符,您将能够避免上述问题。

目标.Net 4.0

目前建议客户在研究完整解决方案的同时继续将其应用程序定位到 .Net 4.0。请注意,由于 .Net 4.5 是就地升级,客户端仍然可以利用 GC 等方面的一些性能改进,而无需专门针对 .Net 4.5 配置文件。对于 Windows RT 开发人员来说,这不是一个选项,因此您需要下面详述的解决方法。

转义前数据

如果可能,客户端可以预先转义数据或用不受影响的字符替换给定的字符。 这就是上述解决方法有效的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-05-04
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2017-08-21
    相关资源
    最近更新 更多