我正在将ClickOnce安装从常规Web服务器移动到Azure Blob存储,并且某些文件存在问题。文件名包含[
]
,CloudBlob.UploadFile
失败,但有例外:
Microsoft.WindowsAzure.Storageclient.StorageException:
访问blob存储时出错:服务器无法验证请求。确保正确形成Authorization标头的值,包括签名。
代码已经使用了一段时间,并且只在名称中带有[
]
的文件上失败,因此我不认为它是“身份验证失败”。在这种特殊情况下,这是在循环中上传的第七个文件。我找到了this link on MSDN about valid file names和this on stack overflow which both show problems with square brackets in URL's and reference UrlEncode
。我添加了对UrlEncode
的电话,但没有帮助。该容器是使用公共访问创建的,因为我们使用它来支持客户下载我们的软件。我们一直在另一个容器中托管“测试”安装,并且没有访问它的权限问题。
我可以上传没有更改名称的文件,然后使用newdesic的Azure存储资源管理器工具重命名文件以添加“路径”,那么我正在做什么呢?
答案 0 :(得分:8)
我看到你正在使用1.7 SDK。这是SDK的一个小编码问题,也存在于v2.0中。让我们看看发生了什么。
account.CreateCloudBlobClient()
.GetContainerReference("temp")
.GetBlobReference("abc[]def.txt")
.UploadFile("myfile.txt");
如果您不对Blob名称进行编码,您最终会得到对以下URL的请求,这会导致身份验证异常:
这是因为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");
这会产生正确编码的网址:
http://account.blob.core.windows.net/temp/abc%5b%5ddef.txt
如果你使用像CloudXplorer这样的工具,你会看到具有正确文件名的blob:
答案 1 :(得分:1)
.Net 4.5中的Uri类有两个已知的中断
•'[',']'字符不再被转义
•'\'字符现在转义为%5C
当服务器尝试验证请求的签名时,这会导致身份验证,因为客户端和服务器上的规范化字符串现在不同。
当出现此问题时,客户端可以使用一些变通方法。正确的解决方案取决于您的具体应用和要求。 避免使用资源名称中的“[”,“]”或“\”字符 通过简单地避免这些字符,您将能够避免上述问题。
目标.Net 4.0
目前,建议客户只需继续将其应用程序定位到.Net 4.0,同时调查完整解决方案。请注意,由于.Net 4.5是一个升级版本,客户端仍然可以利用GC等方面的一些性能改进,而无需专门针对.Net 4.5配置文件。对于Windows RT开发人员,这不是一个选项,因此您需要下面详述的解决方法。
逃生前数据
如果可能,客户端可以预先转义数据或用不受影响的字符替换给定的字符。 这就是上面的解决方法正在发挥作用的原因。