Azure rest api 放置 blob
Posted
技术标签:
【中文标题】Azure rest api 放置 blob【英文标题】:Azure rest api put blob 【发布时间】:2017-06-09 08:29:14 【问题描述】:我正在尝试使用 Azure rest api 放置一个 blob。我成功发出“GET”请求,但“PUT”请求出现问题。当我尝试发出“PUT”请求时,我收到 404 错误(我在 *** 中看到过相同的帖子,但它没有帮助我)。我不确定我使用的 MessageSignature 是否正确(我尝试过 MessageSignaturePut 但没有用)。有什么建议吗?
public void UploadBlobWithRestAPI(string uri, DateTime now)
string blobName = "test.txt";
string method = "PUT";
string sampleContent = "This is sample text.";
int contentLength = Encoding.UTF8.GetByteCount(sampleContent);
string queryString = (new Uri(uri)).Query;
string blobContainerUri = uri.Substring(0, uri.Length - queryString.Length);
string requestUri = string.Format(CultureInfo.InvariantCulture, "0/12", blobContainerUri, blobName, queryString);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
string nnow = now.ToString("R", System.Globalization.CultureInfo.InvariantCulture);
request.Method = method;
request.Headers.Add("x-ms-version", "2015-02-21");
request.Headers.Add("x-ms-date", nnow);
request.ContentType = "text/plain; charset=UTF-8";
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.ContentLength = contentLength;
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
request.Headers.Add("Authorization", AuthorizationHeader(method, now, request, "", ""));
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
MessageBox.Show(resp.StatusCode.ToString());
public string AuthorizationHeader(string method, DateTime now, HttpWebRequest request,
string ifMatch = "", string md5 = "")
string MessageSignature;
string StorageKey = "xxx";
string StorageAccount = "upgradedevstorage";
MessageSignature = String.Format("0\n\n\n1\n5\n\n\n\n2\n\n\n\n34",
method,
(method == "GET" || method == "HEAD") ? String.Empty : request.ContentLength.ToString(),
ifMatch,
GetCanonicalizedHeaders(request),
GetCanonicalizedResource(request.RequestUri, StorageAccount),
md5
);
??? //string MessageSignaturePut= String.Format("0\n\n1\n\n23",
// method,
// "text/plain; charset=UTF-8",
// GetCanonicalizedHeaders(request),
// GetCanonicalizedResource(request.RequestUri, StorageAccount)
// );
byte[] SignatureBytes = System.Text.Encoding.UTF8.GetBytes(MessageSignature);
System.Security.Cryptography.HMACSHA256 SHA256 =
new System.Security.Cryptography.HMACSHA256(Convert.FromBase64String(StorageKey));
string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));
string AuthorizationHeader = "SharedKey " + StorageAccount
+ ":" + Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));
return AuthorizationHeader;
【问题讨论】:
由于您使用的是共享访问签名 (SAS),因此您不需要授权标头。您能告诉我您是如何创建共享访问签名的吗?我有兴趣了解 SAS 中包含的权限。 【参考方案1】:请考虑以下代码 sn-p。这应该适合你。
void UploadBlobWithRestAPI()
string storageKey = "<your access key here>";
string storageAccount = "<your storage account name here>";
string containerName = "<your container name here>";
string blobName = "test.txt";
string method = "PUT";
string sampleContent = "This is sample text.";
int contentLength = Encoding.UTF8.GetByteCount(sampleContent);
string requestUri = $"https://storageAccount.blob.core.windows.net/containerName/blobName";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
string now = DateTime.UtcNow.ToString("R");
request.Method = method;
request.ContentType = "text/plain; charset=UTF-8";
request.ContentLength = contentLength;
request.Headers.Add("x-ms-version", "2015-12-11");
request.Headers.Add("x-ms-date", now);
request.Headers.Add("x-ms-blob-type", "BlockBlob");
request.Headers.Add("Authorization", AuthorizationHeader(method, now, request, storageAccount, storageKey, containerName, blobName));
using (Stream requestStream = request.GetRequestStream())
requestStream.Write(Encoding.UTF8.GetBytes(sampleContent), 0, contentLength);
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
MessageBox.Show(resp.StatusCode.ToString());
public string AuthorizationHeader(string method, string now, HttpWebRequest request, string storageAccount, string storageKey, string containerName, string blobName)
string headerResource = $"x-ms-blob-type:BlockBlob\nx-ms-date:now\nx-ms-version:2015-12-11";
string urlResource = $"/storageAccount/containerName/blobName";
string stringToSign = $"method\n\n\nrequest.ContentLength\n\nrequest.ContentType\n\n\n\n\n\n\nheaderResource\nurlResource";
HMACSHA256 hmac = new HMACSHA256(Convert.FromBase64String(storageKey));
string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
String AuthorizationHeader = String.Format("0 1:2", "SharedKey", storageAccount, signature);
return AuthorizationHeader;
以及Fiddler捕获的流量如下:
【讨论】:
非常感谢。我试过你的代码,但我得到一个(403)禁止错误 它在我的网站上运行良好。那么你能用你最新的代码 sn-p 编辑你的问题吗? 嗨,我已经更新了我的代码以解决我的硬代码问题。你能再试一次吗? 嗨@kostas,很高兴听到这个消息,您可以将其标记为答案,这将有助于其他与您面临类似问题的社区。span> 此解决方案有效,但只能处理最大 4MB 的文件。 Red Gate 的 Robin Shahan 在red-gate.com/simple-talk/cloud/platform-as-a-service/…red-gate.com/simple-talk/cloud/platform-as-a-service/… 上写了一篇关于如何使用 Windows Azure SDK 库分块数据的精彩系列文章。【参考方案2】:上述解决方案仅上传最大 4MB 的文件。我需要一个 PowerShell 版本来满足项目要求,并且使用上面的解决方案走错了路。对于将 BLOB 分块到 Azure RBS 的自定义函数,我在 Red Gate https://www.red-gate.com/simple-talk/cloud/platform-as-a-service/azure-blob-storage-part-4-uploading-large-blobs/ 修改了 Robin Shahan 的版本。
$sdkPath = "C:/Program Files/Microsoft SDKs/Azure/.NET SDK/v2.9/bin/plugins/Diagnostics/Microsoft.WindowsAzure.Storage.dll"
[System.Reflection.Assembly]::LoadFrom($sdkPath);
Add-Type -AssemblyName System.Net.Http
function getMD5HashFromBytes([byte[]]$fileBytes)
$md5 = [System.Security.Cryptography.MD5]::Create()
[byte[]]$hash = $md5.ComputeHash($fileBytes)
return [System.Convert]::ToBase64String($hash)
function setupBlobContainer($account, $secretKey, $container)
$cs = [String]::Format("DefaultEndpointsProtocol=https;AccountName=0;AccountKey=1", $account, $secretKey)
$cloudStorageAccount = [Microsoft.WindowsAzure.Storage.CloudStorageAccount]::Parse($cs)
$cloudBlobClient = [Microsoft.WindowsAzure.Storage.Blob.CloudBlobClient]$cloudStorageAccount.CreateCloudBlobClient()
$cloudBlobContainer = [Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer]$cloudBlobClient.GetContainerReference($container)
return $cloudBlobContainer
function chunkBlob([string]$filepath, [string]$filename, `
[Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer]$cloudBlobContainer)
#ref: https://www.red-gate.com/simple-talk/cloud/platform-as-a-service/azure-blob-storage-part-4-uploading-large-blobs/
$blob = [Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob]$cloudBlobContainer.GetBlockBlobReference($filename)
$blockSize = 256 * 1024; #256 kb
$fileStream = [System.IO.FileStream]::new($filepath, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]::ReadWrite)
$fileSize = $fileStream.Length
#block count is the number of blocks + 1 for the last one
$blockCount = [int]([float]$fileSize / [float]$blockSize) + 1
#List of block ids; the blocks will be committed in the order of this list
$blockIDs = [System.Collections.Generic.List[string]]::new()
#starting block number - 1
$blockNumber = 0
try
$bytesRead = 0 #number of bytes read so far
$bytesLeft = $fileSize; #number of bytes left to read and upload
#do until all of the bytes are uploaded
while($bytesLeft -gt 0)
$blockNumber++;
[int]$bytesToRead;
if($bytesLeft -ge $blockSize)
#more than one block left, so put up another whole block
$bytesToRead = $blockSize
else
#less than one block left, read the rest of it
$bytesToRead = [int]$bytesLeft
#create a blockID from the block number, add it to the block ID list
#the block ID is a base64 string
$blockId = [Convert]::ToBase64String([System.Text.ASCIIEncoding]::ASCII.GetBytes([String]::Format("BlockId0", $blockNumber.ToString("0000000"))))
$blockIDs.Add($blockId)
#set up new buffer with the right size, and read that many bytes into it
[byte[]]$bytes = [System.Byte[]]::new($bytesToRead)
$fileStream.Read($bytes, 0, $bytesToRead)
#calculate the MD5 hash of the byte array
$blockHash = getMD5HashFromBytes $bytes
#upload the block, provide the hash so Azure can verify it
$blob.PutBlock($blockId, [System.IO.MemoryStream]::new($bytes), $blockHash)
#increment/decrement counters
$bytesRead += $bytesToRead
$bytesLeft -= $bytesToRead
$perc = [float][math]::Round( [float]$bytesRead/[float]($bytesRead + $bytesLeft) * 100, 2)
Write-Progress -Activity "Writing '$($filename)'..." -PercentComplete $perc
#commit the blocks
$blob.PutBlockList($blockIDs)
catch [System.Exception]
write-warning $_
finally
if($fileStream)
$fileStream.Dispose()
【讨论】:
以上是关于Azure rest api 放置 blob的主要内容,如果未能解决你的问题,请参考以下文章
在 Azure 存储 [REST] [Azure Blob] 中对 PUT Blob 的 REST api 调用中的身份验证失败