0

我有一个相当简单的方法,它使用 NEW Storage API 创建 SAS 并将 blob 从一个容器复制到另一个容器。

我正在尝试使用它来复制存储帐户之间的 blob。所以我有两个存储帐户,具有完全相同的容器,我试图将一个 blob 从存储帐户的容器复制到另一个存储帐户的容器。

我不知道 SDK 是否是为此而构建的,但它似乎是一个常见的场景。

一些附加信息:

  1. 我在目标容器上创建令牌。是否需要在源和目标上都创建该令牌?注册令牌需要时间吗?我需要为每个请求创建它,还是每个令牌“生命周期”只创建一次?

我应该提到 403 是未经授权的结果 http 错误代码。

  private static string CreateSharedAccessToken(CloudBlobClient blobClient, string containerName)
    {
        var container = blobClient.GetContainerReference(containerName);
        var blobPermissions = new BlobContainerPermissions();

        // The shared access policy provides read/write access to the container for 10 hours:

        blobPermissions.SharedAccessPolicies.Add("SolutionPolicy", new SharedAccessBlobPolicy()
        {
            // To ensure SAS is valid immediately we don’t set start time 
            // so we can avoid failures caused by small clock differences:

            SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1),
            Permissions = SharedAccessBlobPermissions.Write |
                          SharedAccessBlobPermissions.Read
        });


        blobPermissions.PublicAccess = BlobContainerPublicAccessType.Blob; 
        container.SetPermissions(blobPermissions);

        return container.GetSharedAccessSignature(new SharedAccessBlobPolicy(), "SolutionPolicy");

    }

接下来,我使用此令牌调用复制操作,该操作返回 403:

  var uri = new Uri(srcBlob.Uri.AbsoluteUri + blobToken);
            destBlob.StartCopyFromBlob(uri);

我的 Azure.Storage 版本是 2.1.0.2。

如果有帮助,这是完整的复制方法:

    private static void CopyBlobs(
        CloudBlobContainer srcContainer, string blobToken,
        CloudBlobContainer destContainer)
    {
        var srcBlobList
            = srcContainer.ListBlobs(string.Empty, true, BlobListingDetails.All); // set to none in prod (4perf)

        //// get the SAS token to use for all blobs 
        //string token = srcContainer.GetSharedAccessSignature(
        //    new SharedAccessBlobPolicy(), "SolutionPolicy");

        bool pendingCopy = true;

        foreach (var src in srcBlobList)
        {
            var srcBlob = src as ICloudBlob;

            // Determine BlobType:

            ICloudBlob destBlob;
            if (srcBlob.Properties.BlobType == BlobType.BlockBlob)
            {
                destBlob = destContainer.GetBlockBlobReference(srcBlob.Name);
            }
            else
            {
                destBlob = destContainer.GetPageBlobReference(srcBlob.Name);
            }

            // Determine Copy State:

            if (destBlob.CopyState != null)
            {
                switch (destBlob.CopyState.Status)
                {
                    case CopyStatus.Failed:
                        log.Info(destBlob.CopyState);
                        break;

                    case CopyStatus.Aborted:
                        log.Info(destBlob.CopyState);
                        pendingCopy = true;
                        destBlob.StartCopyFromBlob(destBlob.CopyState.Source);
                        return;

                    case CopyStatus.Pending:
                        log.Info(destBlob.CopyState);
                        pendingCopy = true;
                        break;
                }
            }


            // copy using only Policy ID:
            var uri = new Uri(srcBlob.Uri.AbsoluteUri + blobToken);
            destBlob.StartCopyFromBlob(uri);


            //// copy using src blob as SAS
            //var source = new Uri(srcBlob.Uri.AbsoluteUri + token);
            //destBlob.StartCopyFromBlob(source);

        }
    }

最后是帐户和客户(经过审查)代码:

       var credentials = new StorageCredentials("BAR", "FOO");
        var account = new CloudStorageAccount(credentials, true);
        var blobClient = account.CreateCloudBlobClient();
        var sasToken = CreateSharedAccessToken(blobClient, "content");

当我使用 REST 客户端时,这似乎可行……有什么想法吗?

4

3 回答 3

1

还要考虑这个问题:

var uri = new Uri(srcBlob.Uri.AbsoluteUri + blobToken);

可能您正在调用 Uri 的“ToString”方法,该方法会生成 URL 的“Human redable”版本。如果 blobToken 包含特殊字符,例如“+”,这将在存储服务器上导致令牌格式错误,拒绝授予您访问权限。

改用这个:

String uri = srcBlob.Uri.AbsoluteUri + blobToken;
于 2014-07-28T09:25:47.310 回答
0

由于两个 CloudStorageAccount 对象都指向同一个帐户,因此无需 SAS 令牌进行复制就可以正常工作,正如您还提到的那样。

另一方面,您需要可公开访问的 blob 或 SAS 令牌才能从另一个帐户复制。所以你尝试的是正确的,但是你建立了一个容器级别的访问策略,它可能需要 30 秒才能生效,如MSDN中所述。在此时间间隔内,与存储的访问策略关联的 SAS 令牌将失败并显示状态代码 403(禁止),直到访问策略变为活动状态。

我想指出的另一件事是;当您调用 Get*BlobReference 来创建新的 blob 对象时,CopyState 属性将不会被填充,直到您执行诸如 FetchAttributes 之类的 GET/HEAD 操作。

于 2013-10-09T17:49:38.860 回答
0

此任务不需要共享访问令牌。我最终有两个帐户,它工作正常:

        var accountSrc = new CloudStorageAccount(credsSrc, true);
        var accountDest = new CloudStorageAccount(credsSrc, true);

        var blobClientSrc = accountSrc.CreateCloudBlobClient();
        var blobClientDest = accountDest.CreateCloudBlobClient();


        // Set permissions on the container.
        var permissions = new BlobContainerPermissions {PublicAccess = BlobContainerPublicAccessType.Blob};
        srcContainer.SetPermissions(permissions);
        destContainer.SetPermissions(permissions);


   //grab the blob
        var sourceBlob = srcContainer.GetBlockBlobReference("FOO");
        var destinationBlob = destContainer.GetBlockBlobReference("BAR");

        //create a new blob
        destinationBlob.StartCopyFromBlob(sourceBlob);
于 2013-10-07T22:04:32.893 回答