Edited at

fog-aws で S3 の pre-signed url を生成するときにオブジェクトの ACL と Cache-Control を設定する

あまりドキュメントが充実していないように思うので書きます.

コードは最低限のものしか載せていないので, ご自身の環境に合わせて読み替えたり追加したりしてください.


前提


Gemfile

gem 'fog'

gem 'fog-aws'


設定方法

put_object_url の引数の headersCache-Control を, optionsx-amz-acl を指定してあげれば OK です.

例:


.rb

time_to_access = 5.minutes

object_key = 'path/to/the/object'

headers = {
'Cache-Control': 'max-age=3600',
}

options = {
query: {
'x-amz-acl': 'public-read',
}
}

storage = Fog::Storage.new(
provider: 'AWS',
aws_access_key_id: ENV['AWS_ACCESS_KEY_ID'],
aws_secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'],
region: ENV['AWS_REGION'],
)

presigned_url = storage.put_object_url(
ENV['AWS_BUCKET_NAME'],
object_key,
time_to_access.from_now.to_i,
headers,
options
)



注意点

生成した pre-signed url に向けてファイル等を送信するときは, headers で指定したものと同一のリクエストヘッダを設定しましょう.

また fog-aws はデフォルトで PUT メソッドを使ってデータを送信するものとして pre-signed url を生成するので, デフォルト設定に従っているのであれば POST ではなく PUT メソッドを利用しましょう (そうしないと AWS 側からは 403 Forbidden が返ってきてしまいます.)

例えば以下のような


.html

<input type='file' id='fileElem'>


<input> 要素を使ってユーザが選択したファイルをクライアントサイドから送信するコードは, (古の JS や $.ajax で記述すれば) 以下のようになるでしょう:


.js

var fileElem = document.getElementById('fileElem');

fileElem.addEventListener('change', function(e) {
handleFiles(e.target.files);
}, false);

function handleFiles(files) {
for(var i = 0; i < files.length; i++) {
var file = files[i];

$.get({
// 何らかの方法で pre-signed url を返す action が controller 側で定義されているものとします
url: 'presigned_url',
dataType: 'json',
})
.then( function(response) {
return $.ajax({
url: response['presigned_url'],
data: file,
method: 'PUT',
dataType: 'xml',
headers: {
'Cache-Control': 'max-age=3600',
},
processData: false,
contentType: false,
});
})
.done( function() {
console.log('upload completed');
});
}
}



その他

headers では Cache-Control に限らず, x-amz-meta-xxx のようなユーザ定義メタデータも設定できます.


免責事項

本記事のコードを利用した結果, 不利益や損害が発生しても当方は責任を負いかねますので, ご自身の責任にてご利用ください.

特に AWS S3 はセキュリティ周りの設定が重要かと思いますので, 他の記事や公式ドキュメント等も合わせてご参照ください.

また本記事の内容について誤りがありましたら, ご指摘いただければ幸いです.