TL;DR
- GAEへのファイルアップロードにはサイズ制限があるよ
- 制限を超えるアップロードはGCSの"署名付きURL"を使おう
- そのときはドメイン(CORS)制限に気を付けましょう
やりたいこと
GAEでWebアプリケーションをホストして、ファイルをアップロードしてGCSへ格納、それをトリガとしてCloudFunctionsでごにょごにょしたい
- クライアントからGAEへファイルをPOST
- アップロードされたファイルをGAEからGCSへ転送( Google API )する
- その後はGCSのファイル格納イベントをトリガとしてファイル処理をFunctionsに任せる...
このやり方だと、ユーザ認証や認可がGAE1か所でシンプルだしなにより一般的なファイルPOSTプラスGCSのAPIで実装できるので簡単!
動作確認もOK!
の、はずでしたが...
なぜかエラーに
ユーザテスト実施で、「ファイルがアップロードできないんだけど」との報告が
ファイルサイズがでかすぎるですって?!
なるほど。GAEへのリクエストのサイズ制限があるのね。確かに動作確認では数KBのファイルしか使ってなかったカモ。
でも直接GCSへアップロードさせるのもセキュリティを緩めたくないしなぁ。。。
署名付きURL!
ありました!Google推奨プラクティス「署名付きURL」!
これでOK!
つまりこう、
- クライアントからGAEへ「こんなファイルをアップロードするよ!」とリクエスト
- GAEは受信したファイル情報を基にGCSから「署名付きURL」を取得して
- クライアントへその「署名付きURL」を通知
- クライアントからファイル実体をその「署名付きURL」へPUT
- めでたくサイズ制限なしでアップロードが完了して後続の処理へ...
てなわけです。
ちょっと処理が複雑になるとともに、UIを変えずに変更となるとAjaxを使うことになるものの、Google推奨プラクティスでセキュアに実装できますね!
あぁよかった。
さて、動作確認。
え?403って?
署名付きURLへファイルをPUTしようとすると、今度はGCSから403(forbidden)エラーになってる!
Googleの嘘つき~
これは、CORS(オリジン間リソース共有)違反なのね。
つまりは、GAEでホストされているドメイン(大抵自分で取得した)と、GCSの署名付きURLのドメイン(GCSから払い出される)が異なっていて(そらそうだ)、それをGCSはデフォルトで許容しない設定になっているのね。Googleごめんなさい。
GCSのバケットにCORSを構成する
敵 対象が分かれば対応はJustDoIt!
もちろん公式サイトにも記述があります。Googleありがとう!
つまりはGCSへPUTリクエストを出す側のドメイン(この例だとGAEのドメインね)からのアクセスを許してやる。てことね。
この構成は対象のGCSバケットに1度設定してやればOKなので、
- コマンドラインから手で実行してやってもいいけど、
- IaCとしてバケット作成時に自動で構成してもいいし、
- 環境ごと(本番/ステージング/開発)の差異(つまりはクライアントのドメイン)を一か所で管理したければGAEのアプリで最初に構成してやるって手もあるよね。(これだとローカルでGAEシミュレータから動かすときに再構成しやすいしね)
...なんてやり方で構成してやればOK。
皆さんご唱和ください!
「アップエンジン(GAE)へのアップロードは、サイズに注意、ドメイン注意」
私のハマった経験が皆様の良いDX(Developer Experience)の助けになれば幸せです。