Python Flask下载GCP存储桶Blob的App Engine部署及用户端下载问题
你当前的代码仅实现了将GCS存储桶的PDF文件下载到App Engine实例的本地临时目录/tmp,并没有将文件内容返回给访问应用的用户浏览器,因此无法触发用户本地的下载动作。Web场景下要实现用户下载文件,需要将文件内容以符合规范的HTTP响应返回给客户端,由浏览器触发本地保存逻辑。
方案1:直接读取GCS流返回(推荐)
无需将文件写入App Engine实例本地磁盘,直接将GCS文件读取为内存流返回给用户,性能更高,也避免了临时文件的清理问题。
首先导入依赖:
from flask import send_file from google.cloud import storage import io
路由实现代码:
@app.route('/download/<file_name>') def download_file(file_name): # 初始化GCS客户端(生产环境建议省略密钥参数,直接使用App Engine默认服务账号权限) storage_client = storage.Client.from_service_account_json("ebillaae7f0224519.json") bucket = storage_client.get_bucket("bill_storage1") blob = bucket.blob(file_name) # 校验文件是否存在,避免报错 if not blob.exists(): return "文件不存在", 404 # 将GCS文件读取到内存流 file_buffer = io.BytesIO() blob.download_to_file(file_buffer) # 重置流指针到起始位置,否则返回的文件是空的 file_buffer.seek(0) # 返回文件响应,触发浏览器下载 return send_file( file_buffer, mimetype="application/pdf", as_attachment=True, download_name=file_name # 自定义用户下载时的默认文件名 )
方案2:先存到/tmp目录再返回
如果你确实需要先将文件写入实例本地临时目录再返回,可以用以下实现:
import os from flask import send_file from google.cloud import storage @app.route('/download/<file_name>') def download_file(file_name): storage_client = storage.Client.from_service_account_json("ebillaae7f0224519.json") bucket = storage_client.get_bucket("bill_storage1") blob = bucket.blob(file_name) if not blob.exists(): return "文件不存在", 404 temp_path = os.path.join("/tmp", file_name) blob.download_to_filename(temp_path) return send_file( temp_path, mimetype="application/pdf", as_attachment=True, download_name=file_name )
注意事项
- App Engine的
/tmp目录是实例级临时存储,仅当前运行的实例可以访问,实例重启、销毁或扩容时临时文件会丢失,且存储空间上限为实例配置内存的一半,不要存储大文件或作为持久化存储使用。 - 生产环境建议不要将服务账号密钥文件打包部署到App Engine,你可以给App Engine的默认服务账号授予
roles/storage.objectViewer的GCS桶权限,之后直接用storage.Client()初始化即可,不需要传入密钥文件路径,安全性更高。 - 如果文件允许公开访问,也可以生成GCS的签名URL直接返回给用户,让用户直接从GCS存储桶下载,不需要经过Flask应用转发,能大幅降低应用的负载。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

