Python 如何在编写和重命名文件后为 Google 云存储文件生成签名 url?

问题描述

我正在通过将文件从 BigQuery 导出到 Google Cloud 存储来构建文件以供下载。其中一些文件相对较大,因此必须在 BigQuery 导出对它们进行分片后将它们组合在一起。

用户为将在前端生成文件输入文件名。 在后端,我生成一个随机的临时名称,以便我可以将文件组合在一起。

# Job Configuration for the job to move the file to bigQuery
job_config = bigquery.QueryJobConfig()
job_config.destination = table_ref
query_job = client.query(sql,job_config=job_config)
query_job.result()

# Generate a temporary name for the file
fname = "".join(random.choices(string.ascii_letters,k=10))
# Generate Destination URI
destinationURI = info["bucket_uri"].format(filename=f"{fname}*.csv")
extract_job = client.extract_table(table_ref,destination_uris=destinationURI,location="US")
extract_job.result()
# Delete the temporary table,if it doesn't exist ignore it
client.delete_table(f"{info['did']}.{info['tmpid']}",not_found_ok=True)

数据导出完成后,我通过将 blob 组合在一起来取消文件分片。

client = storage.Client(project=info["pid"])
bucket = client.bucket(info['bucket_name'])
all_blobs = list(bucket.list_blobs(prefix=fname))
blob_initial = all_blobs.pop(0)

prev_ind = 0
for i in range(31,len(all_blobs),31):
    # Compose files in chunks of 32 blobs (GCS Limit)
    blob_initial.compose([blob_initial,*all_blobs[prev_ind:i]])
    # PREVENT GCS RATE-LIMIT FOR FILES EXCEEDING ~100GB
    time.sleep(1.0)
    prev_ind = i
else:
    # Compose all remaining files when less than 32 files are left
    blob_initial.compose([blob_initial,*all_blobs[prev_ind:]])

for b in all_blobs:
    # Delete the sharded files
    b.delete()

在所有文件组合成一个文件后,我将 blob 重命名用户提供的文件名。然后我生成一个签名 URL,该 URL 会发布到 Firebase 以供前端提供文件以供下载。

# Rename the file to the user provided filename
bucket.rename_blob(blob_initial,data["filename"])
# Generate signed url to post to firebase
download_url = blob_initial.generate_signed_url(datetime.Now() + timedelta(days=10000))

我遇到的问题是因为使用了文件分片时使用的随机文件名。我选择使用随机文件名而不是用户提供的文件名的原因是因为可能存在多个用户使用相同(认值)文件名提交请求的情况,因此这些边缘情况会导致文件分片出现问题.

当我尝试下载文件时,我得到以下回报:

<Error>
    <Code>NoSuchKey</Code>
    <Message>The specified key does not exist.</Message>
    <Details>No such object: project-id.appspot.com/YMHprgIqMe000000000000.csv</Details> 
</Error>

虽然我重命名文件,但下载地址似乎仍然使用旧文件名。 当我生成签名 URL 时,有没有办法通知 GCS 文件名已更改?

解决方法

看起来好像只需要重新加载 blob!

bucket.rename_blob(blob_initial,data["filename"])

blob = bucket.get(data["filename"])

# Generate signed url to post to firebase
download_url = blob.generate_signed_url(datetime.now() + timedelta(days=10000))