跨存储账户移动Blob时出现‘指定资源不存在’错误排查
跨存储账户移动Blob时StartCopy报错问题
问题描述
尝试将Blob从一个存储账户的容器移动到另一个存储账户的容器,使用以下代码实现:
public void MoveFile(StorageConfig sourceConfig, StorageConfig destinationConfig, string sourceFilename, string destinationFilename) { var sContainer = GetBlobContainerReference(sourceConfig.ConnectionString, sourceConfig.ContainerName); var dContainer = GetBlobContainerReference(destinationConfig.ConnectionString, destinationConfig.ContainerName); var sBlob = sContainer.GetBlockBlobReference(sourceFilename); var dBlob = dContainer.GetBlockBlobReference(destinationFilename); dBlob.StartCopy(sBlob); sBlob.Delete(DeleteSnapshotsOption.IncludeSnapshots); }
源容器和目标容器使用不同凭据,运行代码时dBlob.StartCopy(sBlob)行抛出错误:The specified resource does not exist。
已确认以下状态:
sBlob.Exists() -> true dBlob.Exists() -> false sContainer.Exists() -> true dContainer.Exists() -> true
且sBlob.Delete()执行无异常,说明可正常访问源Blob,疑惑是否需要预先创建目标Blob。
问题原因与解决方案
核心原因
跨存储账户使用StartCopy时,不需要预先创建目标Blob,报错的本质是目标存储账户的凭据没有读取源Blob的权限,而非目标Blob不存在。
具体解决步骤
为源Blob生成共享访问签名(SAS)
由于两个存储账户使用独立凭据,目标账户默认无法读取源Blob。需要给源Blob生成带读权限的SAS,通过SAS URI让目标账户获取源Blob的访问权限,再执行复制操作。修改后的代码示例:
public void MoveFile(StorageConfig sourceConfig, StorageConfig destinationConfig, string sourceFilename, string destinationFilename) { var sContainer = GetBlobContainerReference(sourceConfig.ConnectionString, sourceConfig.ContainerName); var dContainer = GetBlobContainerReference(destinationConfig.ConnectionString, destinationConfig.ContainerName); var sBlob = sContainer.GetBlockBlobReference(sourceFilename); var dBlob = dContainer.GetBlockBlobReference(destinationFilename); // 生成源Blob的SAS,赋予读权限,有效期按需设置 var sasToken = sBlob.GetSharedAccessSignature(new SharedAccessBlobPolicy { Permissions = SharedAccessBlobPermissions.Read, SharedAccessExpiryTime = DateTime.UtcNow.AddHours(1) // 1小时有效期,可根据复制时长调整 }); var sourceBlobSasUri = new Uri(sBlob.Uri + sasToken); // 使用SAS URI启动复制 dBlob.StartCopy(sourceBlobSasUri); // 等待复制完成后再删除源Blob,避免复制中断 while (true) { dBlob.FetchAttributes(); if (dBlob.CopyState.Status != CopyStatus.Pending) break; Thread.Sleep(1000); } // 确认复制成功后删除源Blob if (dBlob.CopyState.Status == CopyStatus.Success) { sBlob.Delete(DeleteSnapshotsOption.IncludeSnapshots); } }关键注意事项
- 禁止提前删除源Blob:原代码中直接调用
sBlob.Delete()会中断复制流程,必须等待复制状态变为Success后再执行删除操作。 - 权限与有效期:生成SAS时需确保至少包含
Read权限,有效期要覆盖复制所需的时间,避免复制过程中SAS过期。
- 禁止提前删除源Blob:原代码中直接调用
内容的提问来源于stack exchange,提问作者William Borgo
相关产品推荐
相关产品推荐

