[英]Unable to set contentType when uploading Azure Blob via REST API
I have the below code which successfully uploads an image to my Azure Blob storage container. 我具有以下代码,该代码已成功将图像上传到我的Azure Blob存储容器。 However, by default it sets the
ContentType
of the stored file to application/octet-stream
I would like to change this to image/jpg
. 但是,默认情况下,它将存储文件的
ContentType
设置为application/octet-stream
我想将其更改为image/jpg
。
To do that I wrote the lines which are in comments below. 为此,我在下面的注释中写了几行。 They set the required content-type headers as far as I understand them from the Azure documentation , however the request now results in a
403 Unauthorized
response instead of a 200
. 据我从Azure 文档中了解的内容,它们设置了所需的内容类型标头,但是,该请求现在导致
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);
}
I can see that the issue is with the generated authorizationHeader
, but I cannot see why as I have followed the guide. 我可以看到问题出在生成的
authorizationHeader
,但是我无法理解为什么遵循了指南。 Can anyone help me shed some light on this. 谁能帮我阐明一下。
Also note that I have to do this through the REST API and not the Microsoft.WindowsAzure.Storage library (annoyingly, as I know it's a fraction of the code when done in that way). 还要注意,我必须通过REST API而不是Microsoft.WindowsAzure.Storage库来完成此操作(令人讨厌的是,因为我知道这样做是代码的一小部分)。
Thanks. 谢谢。
I discovered one issue in your code: 我在您的代码中发现了一个问题:
// DOESN'T WORK:
string stringToSign = requestMethod + "\nimage/jpeg\n\n" + imageBytes.Length + "\n\n\n\n\n\n\n\n\n" + canonicalizedHeaders + "\n" + canonicalizedResource;
Essentially ContentType
should not be the 2nd parameter. 本质上,
ContentType
不应是第二个参数。 2nd parameter is Content-Encoding
based on the documentation
第二个参数是基于
documentation
Content-Encoding
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;
So once you change this, your code should work: 因此,一旦您对此进行了更改,您的代码应该可以正常工作:
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;
Also, you don't need to specify both Content-Type
and x-ms-blob-content-type
. 另外,您无需同时指定
Content-Type
和x-ms-blob-content-type
。 If you define x-ms-blob-content-type
, then it should be included in canonicalizedHeaders
. 如果定义
x-ms-blob-content-type
,则应将其包含在canonicalizedHeaders
。
Here's the code I used to test this: 这是我用来测试的代码:
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");
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.