【问题标题】:Unable to set contentType when uploading Azure Blob via REST API通过 REST API 上传 Azure Blob 时无法设置 contentType
【发布时间】:2016-10-12 11:11:15
【问题描述】:

我有以下代码可以成功地将图像上传到我的 Azure Blob 存储容器。但是,默认情况下它将存储文件的ContentType 设置为application/octet-stream 我想将其更改为image/jpg。

为此,我编写了以下 cmets 中的行。据我所知,他们从Azuredocumentation 中设置了所需的内容类型标头,但是请求现在导致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 库来执行此操作(很烦人,因为我知道以这种方式完成它只是代码的一小部分)。

谢谢。

【问题讨论】:

    标签: c# asp.net azure azure-blob-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 不应该是第二个参数。第二个参数是Content-Encoding,基于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;
    

    所以一旦你改变了这个,你的代码应该可以工作:

            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-Type 和x-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");
            }
        }
    

    【讨论】:

    • 谢谢高拉夫。错误位置的内容类型和 ms-blob-content-type 的组合搞砸了。
    猜你喜欢
    • 2014-10-16
    • 2020-02-08
    • 1970-01-01
    • 1970-01-01
    • 2013-09-21
    • 1970-01-01
    • 1970-01-01
    • 2018-07-11
    • 2015-10-16
    相关资源
    最近更新 更多