S3に対しCORSでJavascriptだけでマルチパートアップロードやダウンロードする場合の必要な設定
色々なサイトで値をアスタリスクで済ませてあるパターンが多くて、なんかモヤっとしたので、必要最小限は何か試してみた結果をここにすまし汁
このTopicの前提条件
- IAMアカウントのキーでアクセスする
- ブラウザのから直接S3に対しアップロードやダウンロードを行う(javacriptのみ)
- アップロードはマルチパートアップロードを使用する
S3のCORS設定
必要になる定義を以下に記載します
AllowOrigin
クロスオリジンなので全てを許可せざるを得ないので値は*
<AllowedOrigin>*</AllowedOrigin>
MaxAgeSeconds
お好みで、値は秒数。見本では2時間相当。
<MaxAgeSeconds>7200</MaxAgeSeconds>
ExposeHeader
晒すレスポンスヘッダー、マルチパートアップロード等でブラウザとS3がやりとりするのに必要な値をレスポンスしてあげる必要がある。ETagとか。
<ExposeHeader>ETag</ExposeHeader>
<ExposeHeader>x-amz-request-id</ExposeHeader>
<ExposeHeader>x-amz-id-2</ExposeHeader>
AllowedHeader
許可するヘッダーのように思えるが、実際には必要なヘッダーの定義。だと思う。
ここに必要なヘッダーが定義されていないとS3とのやりとりが失敗する。
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>User-Agent</AllowedHeader>
<AllowedHeader>x-amz-date</AllowedHeader>
<AllowedHeader>x-amz-user-agent</AllowedHeader>
<AllowedHeader>x-amz-storage-class</AllowedHeader>
<AllowedHeader>x-amz-acl</AllowedHeader>
User-Agentも必要でx-amz-user-agentも必要とか意味不明。
→値を見たら全く違う内容でした。つまりどちらも違う役割。
x-amz-user-agentは「aws-sdk-js/2.0.0-rc13」みたいなSDKの種類やバージョンの値のようです。
必要ヘッダーの検証方法
AllowedHeaderの定義をアスタリスクにした状態でアップロード時のリクエストヘッダーをChromeの開発者ツールで観察し、そこに登場したヘッダー+「x-amz-storage-class」+「x-amz-acl」だけをAllowedHeaderとして編集してそこから一つづつ定義から消しながらマルチパートアップロードをトライアンドエラー。
結果、上記のヘッダー群が残りました。アカウント設定やらACLやらプログラムコードの書き方によっては違いが出てくるかもしれません。
最終結果のヘッダーまとめ
以下がS3へのJavascriptから直接ダウンロード&アップロード(マルチパート)する場合のS3のコントロールパネルから行うCORS設定XMLです。
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>7200</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<ExposeHeader>x-amz-request-id</ExposeHeader>
<ExposeHeader>x-amz-id-2</ExposeHeader>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>User-Agent</AllowedHeader>
<AllowedHeader>X-Amz-Date</AllowedHeader>
<AllowedHeader>X-Amz-User-Agent</AllowedHeader>
<AllowedHeader>x-amz-storage-class</AllowedHeader>
<AllowedHeader>x-amz-acl</AllowedHeader>
</CORSRule>
</CORSConfiguration>
javascript側のおおまかな流れ(マルチパートアップロード編)
詳しくはAWSのjavascript用SDKのドキュメントというかリファレンス見てください。
今回はアカウント情報とかノーガードな流れなので実装する際に気をつけてくだしあ
- フォームでファイルを選択させる
- 送信イベント発火(このタイミングで一旦ファイル情報だけPHPかなんかに送信してシグネチャーの生成とファイルのチェックとかすると良いのでしょう)
- ファイル情報を取得
- AWS.config.updateしたりS3インスタンス生成したり
- s3インスタンスのcreateMultipartUploadメソッド実行してマルチパート処理スタート。戻り値に重要なUploadIdがあるよ!
- ファイルをBlobとして分割送信サイズづつにsliceしながらループ処理でs3インスタンスのuploadPartメソッドを実行
- 戻り値にETagとかあるから値を配列に格納
- 全てのパーツの送信が終わったらs3インスタンスのcompleteMultipartUploadメソッドを実行※この時、引数のオブジェクトの中身にuploadPartメソッドの戻り値の塊が必要なのです。
- どこかでエラーが起きたらs3インスタンスのabortMultipartUploadを読んで中止しましょう。
12GBのファイルをマルチパートアップロードしてみたら、途中大量にエラー出たけど最終的にアップロード出来てました。だいたい1時間半位かかりました。
※2500分割位で送信して5000件以上エラー出てた。
追記
2015/12/10現在では自分は以下の様な設定で使っています。
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>HEAD</AllowedMethod>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<AllowedMethod>DELETE</AllowedMethod>
<MaxAgeSeconds>7200</MaxAgeSeconds>
<ExposeHeader>ETag</ExposeHeader>
<ExposeHeader>x-amz-request-id</ExposeHeader>
<ExposeHeader>x-amz-id-2</ExposeHeader>
<ExposeHeader>x-amz-meta-custom-header</ExposeHeader>
<AllowedHeader>Origin</AllowedHeader>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>Content-Type</AllowedHeader>
<AllowedHeader>User-Agent</AllowedHeader>
<AllowedHeader>X-Amz-Date</AllowedHeader>
<AllowedHeader>X-Amz-User-Agent</AllowedHeader>
<AllowedHeader>x-amz-storage-class</AllowedHeader>
<AllowedHeader>x-amz-acl</AllowedHeader>
<AllowedHeader>x-amz-security-token</AllowedHeader>
</CORSRule>
</CORSConfiguration>
いつの間にかExposeHeaderにx-amz-meta-custom-headerと
AllowedHeaderにx-amz-security-tokenを追加してました。
Cognito使うようになったからかな。。。
また、AllowedHeaderにOriginを追加しているのはこうしないとSafariの場合に
403エラーがでるので追加しています。仕組みは分かっていません。