使用Blob.rewrite()跨存储桶复制文件时GCF报NotFound错误
使用Google Cloud Function(GCF)的Blob.rewrite()方法在Google Cloud Storage(GCS)存储桶间复制文件时,触发NotFound错误:
NotFound: 404 POST https://storage.googleapis.com/storage/v1/b/ca-app-corp-finance-dev-444/o/process%2Ffin_essbase%2Fdata%2Fincoming%2Fessbase%2Fkey.ppk/rewriteTo/b/gcf-v2-uploads-632430838198-us-east1/o/key.ppk?prettyPrint=false: No such object: ca-app-corp-finance-dev-444/process/fin_essbase/data/incoming/essbase/key.ppk
场景与代码
GCF配置为:源存储桶gcf-v2-uploads-632430838198-us-east1有新文件上传时触发函数,目标是将文件复制到目标存储桶ca-app-corp-finance-dev-444的process/fin_essbase/data/incoming/essbase/路径下,使用Blob.rewrite()实现。代码片段如下:
from google.cloud import storage def transfer_file(data, context): source_bucket_name = "gcf-v2-uploads-632430838198-us-east1" destination_bucket_name = "ca-app-corp-finance-dev-444" target_path = "process/fin_essbase/data/incoming/essbase/" filename = "key.ppk" storage_client = storage.Client() source_bucket = storage_client.bucket(source_bucket_name) destination_bucket = storage_client.bucket(destination_bucket_name) source_blob = source_bucket.blob(filename) destination_blob = destination_bucket.blob(target_path + filename) # Check if the destination blob already exists if destination_blob.exists(): print(f"Destination blob {destination_blob.name} already exists.") else: try: # Perform a rewrite operation to copy the content token = source_blob.rewrite(destination_blob) # Wait for the rewrite to complete token.result() # Delete the source blob source_blob.delete() print(f"File {filename} transferred successfully.") except Exception as e: print(f"An error occurred: {e}")
已确认源对象存在、存储桶与路径无误,服务账号拥有源桶读取、目标桶写入权限,但仍触发错误。
确认rewrite操作的对象方向
从错误URL可见,API请求尝试将目标桶的对象重写到源桶,与业务逻辑完全相反。检查代码中source_blob和destination_blob的初始化逻辑,确保source_bucket对应源存储桶、source_blob指向源桶中存在的对象;destination_bucket对应目标存储桶、destination_blob指向目标路径。替换硬编码文件名,使用触发事件传递的对象名
代码硬编码了filename = "key.ppk",但GCF触发事件会通过data['name']传递实际上传的文件名。若上传文件不是key.ppk,source_blob会指向不存在的对象,间接导致rewrite逻辑异常。修改代码使用触发事件的文件名:filename = data['name'] # 若需去掉源桶中的路径前缀,可添加处理:filename = os.path.basename(data['name'])补全目标存储桶的权限配置
尽管服务账号有目标桶写入权限,但destination_blob.exists()需要storage.objects.get权限,rewrite操作还需目标桶的storage.objects.create和storage.objects.update权限。确认服务账号的IAM角色包含:- 源桶:
roles/storage.objectViewer(或自定义包含storage.objects.get的权限) - 目标桶:
roles/storage.objectCreator+roles/storage.objectViewer(或直接使用roles/storage.objectAdmin)
- 源桶:
检查存储桶区域与跨区域访问限制
若源桶和目标桶处于不同区域,确认是否存在VPC限制、组织政策等阻碍跨区域资源访问的配置。可临时将测试文件放在同区域桶中,验证rewrite功能是否正常。更新Google Cloud Storage Python客户端库
旧版本客户端库可能存在rewrite方法的参数逻辑或API调用问题。在Function的requirements.txt中指定最新版本:google-cloud-storage>=2.15.0添加源对象存在性前置检查
在执行rewrite前,先确认源对象存在,避免因源对象不存在导致的间接错误:if not source_blob.exists(): print(f"Source blob {source_blob.name} does not exist.") return
内容的提问来源于stack exchange,提问作者Someone

