2016-10-12 52 views
0

我有下面的代码,它已成功将图像上传到Azure Blob存储容器。但是,默认情况下,它将存储文件的ContentType设置为application/octet-stream我想将其更改为image/jpg通过REST API上传Azure Blob时无法设置contentType

要做到这一点,我写了下面评论中的行。据我所知,他们设置了所需的内容类型标题,但是现在请求的结果是403 Unauthorized而不是200

private static void PutBlob(string filenameToSave) 
{ 
    var requestMethod = "PUT"; 
    var urlPath = _storageContainer + "/" + filenameToSave; 
    var storageServiceVersion = "2015-12-11"; 
    var date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); 
    var blobType = "BlockBlob"; 
    var imageBytes = GetImageBytes(); 
    var canonicalizedResource = "/" + _storageAccount + "/" + urlPath; 

    // DOESN'T WORK: 
    var canonicalizedHeaders = "x-ms-blob-type:" + blobType + "\nx-ms-blob-content-type:image/jpeg\nx-ms-date:" + date + "\nx-ms-version:" + storageServiceVersion; 
    // WORKS: 
    //var canonicalizedHeaders = "x-ms-blob-type:" + blobType + "\nx-ms-date:" + date + "\nx-ms-version:" + storageServiceVersion; 

    // DOESN'T WORK: 
    string stringToSign = requestMethod + "\nimage/jpeg\n\n" + imageBytes.Length + "\n\n\n\n\n\n\n\n\n" + canonicalizedHeaders + "\n" + canonicalizedResource; 
    // WORKS: 
    //string stringToSign = requestMethod + "\n\n\n" + imageBytes.Length + "\n\n\n\n\n\n\n\n\n" + canonicalizedHeaders + "\n" + canonicalizedResource; 

    string authorizationHeader = GenerateSharedKey(stringToSign, _storageKey, _storageAccount); 

    var uri = $"https://{_storageAccount}.blob.core.windows.net/{urlPath}"; 
    var request = (HttpWebRequest)WebRequest.Create(uri); 
    request.Method = requestMethod; 
    request.ContentType = "image/jpeg"; // DOESN'T WORK 

    request.Headers.Add("x-ms-blob-content-type", "image/jpeg"); // DOESN'T WORK 
    request.Headers.Add("x-ms-blob-type", blobType); 
    request.Headers.Add("x-ms-date", date); 
    request.Headers.Add("x-ms-version", storageServiceVersion); 
    request.Headers.Add("Authorization", authorizationHeader); 

    var stream = request.GetRequestStream(); 
    stream.Write(imageBytes, 0, imageBytes.Length); 

    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
    { 
     // check the response status here, 200/201 means it worked 

     Console.WriteLine("File uploaded"); 
    } 
} 

private static string GenerateSharedKey(string stringToSign, string key, string account) 
{ 
    string signature; 
    var unicodeKey = Convert.FromBase64String(key); 
    using (var hmacSha256 = new HMACSHA256(unicodeKey)) 
    { 
     var dataToHmac = Encoding.UTF8.GetBytes(stringToSign); 
     signature = Convert.ToBase64String(hmacSha256.ComputeHash(dataToHmac)); 
    } 
    return string.Format(CultureInfo.InvariantCulture, "{0} {1}:{2}", "SharedKey", account, signature); 
} 

我可以看到的问题是与生成authorizationHeader,但我不明白为什么,因为我也跟着指导。任何人都可以帮我解释一下这个。

另外请注意,我必须通过REST API而不是Microsoft.WindowsAzure.Storage库(令人讨厌的是,因为我知道这是以这种方式完成的代码的一小部分)。

谢谢。

回答

1

我发现在你的代码的一个问题:

// DOESN'T WORK: 
    string stringToSign = requestMethod + "\nimage/jpeg\n\n" + imageBytes.Length + "\n\n\n\n\n\n\n\n\n" + canonicalizedHeaders + "\n" + canonicalizedResource; 

本质ContentType不应该是第二个参数。第二个参数是基于documentation

StringToSign = VERB + "\n" + 
       Content-Encoding + "\n" + 
       Content-Language + "\n" + 
       Content-Length + "\n" + 
       Content-MD5 + "\n" + 
       Content-Type + "\n" + 
       Date + "\n" + 
       If-Modified-Since + "\n" + 
       If-Match + "\n" + 
       If-None-Match + "\n" + 
       If-Unmodified-Since + "\n" + 
       Range + "\n" + 
       CanonicalizedHeaders + 
       CanonicalizedResource; 

Content-Encoding所以一旦你改变这一点,您的代码应工作:

 string stringToSign = requestMethod + "\n" + 
      "\n" + //Content Encoding 
      "\n" + //Content Language 
      imageBytes.Length + "\n" + //Content Length 
      "\n" + //Content MD5 
      "image/jpeg" + "\n" + //Content Type 
      "\n" + //Date 
      "\n" + //If - Modified - Since 
      "\n" + //If - Match 
      "\n" + //If - None - Match 
      "\n" + //If - Unmodified - Since 
      "\n" + //Range + 
      canonicalizedHeaders + "\n" + 
      canonicalizedResource; 

而且,你不需要同时指定Content-Typex-ms-blob-content-type。如果您定义了x-ms-blob-content-type,那么它应该包含在canonicalizedHeaders中。

这是我用来测试这个代码:

private static void PutBlob(string filenameToSave) 
    { 
     var requestMethod = "PUT"; 
     var urlPath = "<container-name>" + "/" + filenameToSave; 
     var storageServiceVersion = "2015-12-11"; 
     var date = DateTime.UtcNow.ToString("R", CultureInfo.InvariantCulture); 
     var blobType = "BlockBlob"; 
     var imageBytes = File.ReadAllBytes(@"File Path"); 
     var canonicalizedResource = "/" + accountName + "/" + urlPath; 

     // DOESN'T WORK: 
     //var canonicalizedHeaders = "x-ms-blob-type:" + blobType + "\nx-ms-blob-content-type:image/jpeg\nx-ms-date:" + date + "\nx-ms-version:" + storageServiceVersion; 
     // WORKS: 
     var canonicalizedHeaders = "x-ms-blob-type:" + blobType + "\nx-ms-date:" + date + "\nx-ms-version:" + storageServiceVersion + "\n"; 

     // DOESN'T WORK: 
     //string stringToSign = requestMethod + "\nimage/jpeg\n\n" + imageBytes.Length + "\n\n\n\n\n\n\n\n\n" + canonicalizedHeaders + "\n" + canonicalizedResource; 
     // WORKS: 
     //string stringToSign = requestMethod + "\n\n\n" + imageBytes.Length + "\n\n\n\n\n\n\n\n\n" + canonicalizedHeaders + "\n" + canonicalizedResource; 
     string stringToSign = requestMethod + "\n" + 
      "\n" + //Content Encoding 
      "\n" + //Content Language 
      imageBytes.Length + "\n" + //Content Length 
      "\n" + //Content MD5 
      "image/jpeg" + "\n" + //Content Type 
      "\n" + //Date 
      "\n" + //If - Modified - Since 
      "\n" + //If - Match 
      "\n" + //If - None - Match 
      "\n" + //If - Unmodified - Since 
      "\n" + //Range + 
      canonicalizedHeaders + 
      canonicalizedResource; 
     string authorizationHeader = GenerateSharedKey(stringToSign, accountKey, accountName); 

     var uri = "https://" + accountName + ".blob.core.windows.net/" + urlPath; 

     var request = (HttpWebRequest)WebRequest.Create(uri); 
     request.Method = requestMethod; 
     request.ContentType = "image/jpeg"; // DOESN'T WORK 

     //request.Headers.Add("x-ms-blob-content-type", "image/jpeg"); // DOESN'T WORK 
     request.Headers.Add("x-ms-blob-type", blobType); 
     request.Headers.Add("x-ms-date", date); 
     request.Headers.Add("x-ms-version", storageServiceVersion); 
     request.Headers.Add("Authorization", authorizationHeader); 

     var stream = request.GetRequestStream(); 
     stream.Write(imageBytes, 0, imageBytes.Length); 

     using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
     { 
      // check the response status here, 200/201 means it worked 

      Console.WriteLine("File uploaded"); 
     } 
    } 
+0

感谢拉夫。它是错误位置的内容类型和“ms-blob-content-type”的组合,这让它变得糟糕。 –