はじめに
これがやりたかった。ただし、node.jsで。
http://qiita.com/yuku_t/items/40b7daf018d3dab48974
PHP版で解りやすいソースを貼ってくれているのを発見。これを元にアクションする事にした。
http://qiita.com/supertaihei02/items/a4f663d837e51f2f72b0
簡単な置き換えと思ったら知識の足らなかった事
基本は置き換えただけなので、たいした事は無いと思ったが、S3のバケットのCrossOriginは改めて調べないといけなかったので記しておく。
http://stackoverflow.com/questions/4717006/amazon-s3-and-cross-origin-resource-sharing-cors
を経由して
http://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html
に辿り着いた。どこから設定するのかよくわからなかったので、ちょっと探す。
こんな感じでどんなアクセスを許すのかを調整する。ここではlocalhost:3000からはイロイロ許可した。
コード
node.js、expressでmoment.jsを導入している。routesが下記。
app.get('/upload', routes.upload);
をしている。
var moment = require('moment');
var crypto = require('crypto');
function createS3bucket(params) {
function base64_encode(val) {
var b = new Buffer(val);
return b.toString('base64');
}
var accesskey = '[accesskey]' // TODO
var secret = '[secret]'; // TODO
var bucket = '[bucket]'; // TODO
var key = '[path/to/file]'; // TODO
var aminlater = moment(new Date().getTime() + 1000 * 60); //a minit later
var expiration = aminlater.utc().format('YYYY-MM-DDTHH:mm:ss[Z]');
var acl = 'public-read'; // set acl (private | public-read | public-read-write | authenticated-read | bucket-owner-read | bucket-owner-full-control)
var status = '200'; // return this status code when upload success.
var ctype = params['ctype'];
var clength = params['clength'];
var policy = {
"expiration": expiration,
"conditions": [
{"bucket": bucket},
{"key": key},
{"acl": acl},
{"success_action_status": status},
{"Content-Type": ctype},
["content-length-range", clength, clength]
]
};
//console.log('policy', policy);
var encodedPolicy = base64_encode(JSON.stringify(policy));
var sh = crypto.createHmac('sha1', secret);
sh.update(encodedPolicy);
var signature = sh.digest('base64');
var ret = {
'url': 'http://' + bucket + '.s3.amazonaws.com/',
'form': {
'AWSAccessKeyId': accesskey,
'signature': signature,
'policy': encodedPolicy,
'key': key,
'acl': acl,
'success_action_status': status,
'Content-Type': ctype
}
};
//sconsole.log('ret', ret);
return ret;
}
exports.upload = function (req, res) {
var ret = createS3bucket(req.query);
res.json(ret);
};
ビューは下記。基本的に
http://qiita.com/supertaihei02/items/a4f663d837e51f2f72b0
のままです。エラー確認がしやすい用のログを入れた程度。
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<script src="//code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
$().ready(function () {
$('#s3form input[type="file"]').on('change', function (e) {
// ファイルの情報をチェックしてパラメータ生成.必要であれば許可ファイル以外をはじく.
var file = e.target.files[0];
var data = {ctype: file.type, clength: file.size};
// サーバからpolicyとsignatureを取得.
var $form = $('#s3form');
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
dataType: 'json',
data: data
}).done(function (data) {
// サーバが返した情報をそのまま使ってFormDataを作る.
var name, fd = new FormData();
for (name in data.form) if (data.form.hasOwnProperty(name)) {
fd.append(name, data.form[name]);
}
fd.append('file', file); // ファイル添付.
// 送信
var xhr = new XMLHttpRequest();
xhr.open('POST', data.url, true);
xhr.onreadystatechange = function (aEvt) {
if (xhr.readyState == 4) {
if (xhr.status == 200)
console.log(xhr.responseText);
else{
console.log('error');
console.log(xhr.responseText);
}
}
};
xhr.send(fd);
})
});
});
</script>
</head>
<body>
<form id="s3form" action="upload" method="get" enctype="multipart/form-data">
<input type="file" name="file"/>
</form>
</body>
</html>
おしまいに
コードを公開してくれていた方々のおかげで素晴らしく時間短縮ができたので、感謝しつつ自分の成果も上げさせて戴いた。丸パクリごめんなさい。