Azure rest api 放置 blob

Azure rest api put blob

我正在尝试用 Azure rest 放置一个 blob api。我成功发出了 "GET" 请求,但我遇到了 "PUT" 请求的问题。当我尝试发出 "PUT" 请求时,我收到 404error(我在 Whosebug 中看到了相同的 post,但它对我没有帮助)。我不确定我使用的 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}/{1}{2}", 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\n{1}\n{5}\n\n\n\n{2}\n\n\n\n{3}{4}",
        method,
        (method == "GET" || method == "HEAD") ? String.Empty : request.ContentLength.ToString(),
        ifMatch,
        GetCanonicalizedHeaders(request),
        GetCanonicalizedResource(request.RequestUri, StorageAccount),
        md5
        );

 ???   //string MessageSignaturePut= String.Format("{0}\n\n{1}\n\n{2}{3}",
    //    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;
}

请考虑以下代码片段。这应该适合你。

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\n{request.ContentLength}\n\n{request.ContentType}\n\n\n\n\n\n\n{headerResource}\n{urlResource}";

    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抓取的流量如下:

上述解决方案最多只能上传 4MB 的文件。我需要一个 PowerShell 版本来满足项目要求,但使用上述解决方案却走错了路。对于将 BLOB 分块到 Azure RBS 的自定义函数,我在 https://www.red-gate.com/simple-talk/cloud/platform-as-a-service/azure-blob-storage-part-4-uploading-large-blobs/.

的 Red Gate 修改了 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("BlockId{0}", $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()
        }
    }
}