S3に対しCORSでJavascriptだけでマルチパートアップロードやダウンロードする場合の必要な設定
色々なサイトで値をアスタリスクで済ませてあるパターンが多くて、なんかモヤっとしたので、必要最小限は何か試してみた結果をここにすまし汁
このTopicの前提条件
●IAMアカウントのキーでアクセスする ●ブラウザのから直接S3に対しアップロードやダウンロードを行う(javacriptのみ) ●アップロードはマルチパートアップロードを使用するS3のCORS設定
必要になる定義を以下に記載しますAllowOrigin
クロスオリジンなので全てを許可せざるを得ないので値は*<AllowedOrigin>*</AllowedOrigin>
MaxAgeSeconds
お好みで、値は秒数。見本では2時間相当。<MaxAgeSeconds>7200</MaxAgeSecon
ds>
ExposeHeader
晒すレスポンスヘッダー、マルチパートアップロード等でブラウザとS3がやりとりするのに必要な値をレスポンスしてあげる必要がある。ETagとか。<ExposeHeader>ETag</ExposeHeader
>
<ExposeHeader>x-amz-request-id</
ExposeHeader>
<ExposeHeader>x-amz-id-2</Expose
Header>
AllowedHeader
許可するヘッダーのように思えるが、実際には必要なヘッダーの定義。だと思う。 ここに必要なヘッダーが定義されていないとS3とのやりとりが失敗する。<AllowedHeader>Authorization</Al
lowedHeader>
<AllowedHeader>Content-Type</All
owedHeader>
<AllowedHeader>User-Agent</Allow
edHeader>
<AllowedHeader>x-amz-date</Allow
edHeader>
<AllowedHeader>x-amz-user-agent<
/AllowedHeader>
<AllowedHeader>x-amz-storage-cla
ss</AllowedHeader>
<AllowedHeader>x-amz-acl</Allowe
dHeader>
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エラーがでるので追加しています。仕組みは分かっていません。