概要
- GCSからデータダウンロードしたいですが、GAEを利用しているとタイムアウト値がstandardで60秒、flexibleで60分なので、容量がでかい場合、直接GCSからデータダウンロードしたくなると思います
- 署名付きでやると公開されてしまうので嫌ですが、発行して直後に有効期限が切れて且つダウンロードは進むの要件でおkならそれでいいなってので試した内容になります
- 今回はGCSへ保存しているデータは動画になります。利用する際は保存しているデータ形式あわせて修正すると良いです
ソースコード
from google.cloud import storage
from google.api_core.exceptions import NotFound
import os
from datetime import timedelta
def get_bucket():
project_id = "" # 設定してください
client = storage.Client(project_id)
bucket_name = "" # 設定してください
return client.get_bucket(bucket_name)
def get_suffix(content_type):
# TODO: アップロードされる拡張子が増えたらここに追加.
content_types = {
'video/webm': '.webm'
}
suffix = content_types.get(content_type)
if suffix is None:
raise Exception('存在しない拡張子エラー: {}'.format(content_type))
return suffix
def generate_signed_url(blob, blob_name, suffix):
"""署名付きダウンロードURLを発行する"""
# response_typeでheaderをいじることができる(今回はダウンロードURLを発行する)
response_type = \
f"content-disposition=attachment; filename={blob_name}.{suffix}"
return blob.generate_signed_url(
version="v4",
expiration=timedelta(seconds=30),
method="GET",
response_type=response_type
)
def generate_download_url(filename):
try:
bucket = get_bucket()
# blobを取得したらダウンロードせずとも拡張子がわかる.
blob = bucket.get_blob(filename)
suffix = get_suffix(blob.content_type)
url = generate_signed_url(
blob,
filename,
suffix
)
return url
except NotFound as e:
# 存在しないファイルをGCSからdownloadしようとした場合
print(e)
except Exception as e:
print(e)
return None
if __name__ == '__main__':
url = generate_download_url('hogehoge')
print(url)
簡易説明
環境
- Python 3.10.x
準備
requirements.txt
に下記追記して、インストールしましょう。
google-cloud-storage==2.4.0
$ pip install -r requirements.txt
あと環境変数にサービスアカウントのパスを指定してあげてください(発行方法や設定については省略)
GOOGLE_APPLICATION_CREDENTIALS_FILENAME=/project_root/credentials/hogehoge.json
Response headerの修正
動画の場合、署名付きURLを発行するだけだと、ブラウザでストリームで再生するようになりますが、ファイルとしてダウンロードしたいので、ヘッダーをつけています。 response_type
にヘッダーをつけることができました。神!
有効期限が短いですが、発行後、すぐに踏んでダウンロードが開始することができるなら問題なしです。有効期限はアクセスの期限なので、ダウンロード中には適応されません。
今回は取得したURLをフロント側で <a></a>
に設定して動的にclickさせるで対応しました。
response_type = f"content-disposition=attachment; filename={blob_name}.{suffix}"
return blob.generate_signed_url(
version="v4",
expiration=timedelta(seconds=30), # 署名の有効期限
method="GET",
response_type=response_type
)