4

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

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

该代码已经使用了一段时间,并且只[ ]在名称中的文件上失败,所以我不认为这是“身份验证失败”。在这种特殊情况下,这是循环上传的第七个文件。我在 MSDN 上找到了这个关于有效文件名的链接这个关于堆栈溢出的链接,它们都显示了 URL 和参考中方括号的问题UrlEncode。我添加了一个电话UrlEncode,但没有帮助。该容器是通过公共访问创建的,因为我们使用它来支持客户下载我们的软件。我们一直在另一个容器中托管“测试”安装,并且访问该容器也没有权限问题。

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

4

2 回答 2

8

我看到您使用的是 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:

在此处输入图像描述

于 2012-12-03T20:35:26.663 回答
1

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

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

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

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

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

目标.Net 4.0

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

逃逸前数据

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

于 2013-11-19T22:12:25.520 回答