【问题标题】:Copy Blob in Azure Blob Storage using Java v12 SDK使用 Java v12 SDK 在 Azure Blob 存储中复制 Blob
【发布时间】:2021-01-04 20:26:42
【问题描述】:

我的应用程序位于 Kubernetes 集群中,我正在使用 Java v12 SDK 与 Blob 存储进行交互。为了授权 Blob 存储,我使用了托管身份。

我的应用程序需要在一个容器中复制 blob。我还没有找到任何具体的recommendations or examples 应该如何使用 SDK 进行复制。

我认为在使用模拟器时以下方法有效

copyBlobClient.copyFromUrl(sourceBlobClient.getBlobUrl());

但是,当它在集群中执行时,我收到以下错误

<Error>
   <Code>CannotVerifyCopySource</Code>
   <Message>The specified resource does not exist. RequestId: __ Time: __ </Message>
</Error> 

消息说“资源不存在”,但 blob 显然在那里。不过,我的容器有私人访问权限。

现在,当我将公共访问级别更改为“Blob(仅限 Blob 的匿名读取访问)”时,一切正常。但是,我不接受公共访问。

主要问题 - 使用 Java v12 SDK 实现复制 blob 的正确方法是什么。

在我的情况下我可能会错过什么或配置错误?

最后是错误信息本身。有一部分写着“CannotVerifyCopySource”,它可以帮助您了解某些东西可以访问,但消息部分显然具有误导性。错误不应该更明确吗?

【问题讨论】:

标签: azure azure-storage azure-blob-storage azure-java-sdk


【解决方案1】:

如果您想使用 Azure JAVA SDK 复制带有 Azure MSI 的 blob,请参考以下详细信息

  • 在存储帐户之间复制 Blob

如果使用 Azure MSI 在存储帐户之间复制 blob。我们应该做以下动作

  1. 将 Azure Storage Blob Data Reader 分配给源容器中的 MSI

  2. 将 Azure Storage Blob Data Contributor 分配给 dest 容器中的 MSI。此外,当我们复制 blob 时,我们需要写入权限才能将内容写入 blob

  3. 为 blob 生成 SAS 令牌。如果源 blob 是公开的,我们可以直接使用源 blob URL 而无需 sas token。

例如

 try {
            BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
                    .endpoint("https://<>.blob.core.windows.net/" )
                    .credential(new DefaultAzureCredentialBuilder().build())
                    .buildClient();
            // get User Delegation Key
            OffsetDateTime delegationKeyStartTime = OffsetDateTime.now();
            OffsetDateTime delegationKeyExpiryTime = OffsetDateTime.now().plusDays(7);
            UserDelegationKey key =blobServiceClient.getUserDelegationKey(delegationKeyStartTime,delegationKeyExpiryTime);

            BlobContainerClient sourceContainerClient = blobServiceClient.getBlobContainerClient("test");
            BlobClient sourceBlob = sourceContainerClient.getBlobClient("test.mp3");
            // generate sas token
            OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1);
            BlobSasPermission permission = new BlobSasPermission().setReadPermission(true);

            BlobServiceSasSignatureValues myValues = new BlobServiceSasSignatureValues(expiryTime, permission)
                    .setStartTime(OffsetDateTime.now());
            String sas =sourceBlob.generateUserDelegationSas(myValues,key);

            // copy
            BlobServiceClient desServiceClient = new BlobServiceClientBuilder()
                    .endpoint("https://<>.blob.core.windows.net/" )
                    .credential(new DefaultAzureCredentialBuilder().build())
                    .buildClient();
            BlobContainerClient desContainerClient = blobServiceClient.getBlobContainerClient("test");
            String res =desContainerClient.getBlobClient("test.mp3")
                    .copyFromUrl(sourceBlob.getBlobUrl()+"?"+sas);
            System.out.println(res);
        } catch (Exception e) {
            e.printStackTrace();
        }

  • 在同一帐户中复制

如果您使用 Azure MSI 在同一存储帐户中复制 blob,建议您将 Storage Blob Data Contributor 分配给存储帐户中的 MSI。然后我们可以使用copyFromUrl方法进行复制操作。

例如

一个。在帐户级别将 Storage Blob Data Contributor 分配给 MSI

b.代码

  try {
            BlobServiceClient blobServiceClient = new BlobServiceClientBuilder()
                    .endpoint("https://<>.blob.core.windows.net/" )
                    .credential(new DefaultAzureCredentialBuilder().build())
                    .buildClient();

            BlobContainerClient sourceContainerClient = blobServiceClient.getBlobContainerClient("test");
            BlobClient sourceBlob = sourceContainerClient.getBlobClient("test.mp3");

            BlobContainerClient desContainerClient = blobServiceClient.getBlobContainerClient("output");
            String res =desContainerClient.getBlobClient("test.mp3")
                    .copyFromUrl(sourceBlob.getBlobUrl());
            System.out.println(res);
        } catch (Exception e) {
            e.printStackTrace();
        }

更多详情请参考herehere

【讨论】:

  • 感谢您提供了很大帮助的详细答案。但是,出于某种原因,即使在同一个存储帐户中并使用 MSI,我也需要添加 sas 令牌。所以我的 finan 解决方案看起来像这样: String sasToken = sourceBlobClient.generateSasToken(); copyBlobClient.copyFromUrl(sourceBlobClient.getBlobUrl() + "?" + sasToken);
【解决方案2】:

我在使用适用于 Azure 的 Java SDK 时遇到了同样的问题,我通过使用 URL + SAS 令牌复制 blob 解决了这个问题。实际上,如果您没有正确的访问权限,您通过 URL 获取的资源将不会显示为可用。这是我用来解决问题的代码:

BlobClient sourceBlobClient = blobServiceClient
                        .getBlobContainerClient(currentBucketName)
                        .getBlobClient(sourceKey);
// initializing the copy blob client
BlobClient copyBlobClient = blobServiceClient
        .getBlobContainerClient(newBucketName)
        .getBlobClient(newKey);
// Creating the SAS Token to get the permission to copy the source blob 
OffsetDateTime expiryTime = OffsetDateTime.now().plusDays(1);
BlobSasPermission permission = new BlobSasPermission().setReadPermission(true);
BlobServiceSasSignatureValues values = new BlobServiceSasSignatureValues(expiryTime, permission)
.setStartTime(OffsetDateTime.now());
String sasToken = sourceBlobClient.generateSas(values);

//Making the copy using the source blob URL + generating the copy 
var res = copyBlobClient.copyFromUrl(sourceBlobClient.getBlobUrl() +"?"+ sasToken);

【讨论】:

    猜你喜欢
    • 2022-01-27
    • 2021-10-05
    • 2020-05-13
    • 2021-11-08
    • 2020-11-30
    • 2021-04-22
    • 2020-11-25
    • 2015-06-20
    • 2016-09-21
    相关资源
    最近更新 更多