AWS SDK for JavaScriptを使ってS3にダイレクトでファイルをアップロードする

AWS SDK for JavaScriptがリリースされました。これにより、例えばS3にJavaScriptのファイルを配置して、クライアントサイドでJavaScriptを実行、その中でS3へのファイルアップロードの処理を行えば、別途S3へのアップロードを行うためのWebサーバが必要なくなります。

まず、最初にJavaScriptを使って、S3のバケットに対してlistObjectsしてみます。そのJavaScriptを含むHTMLファイルが以下です。

<head>
<title>Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script>
<script type="text/javascript">
<!--
AWS.config.update({accessKeyId: 'ACCESS_KEY_ID', secretAccessKey: 'SECRET_ACCESS_KEY'});
var s3 = new AWS.S3({region: 'ap-northeast-1', maxRetries: 15});
s3.listObjects({Bucket: 'BUCKET_NAME'}, function(error, data) {
  if (error) {
    console.log(error); // an error occurred
  } else {
    console.log(data); // request succeeded
  }
});
// -->
</script>
</body>
</html>

これをWebサーバもしくはS3上に配置します。
この作業だけでは、Access Deniedと表示されてしまうので、さらに該当するバケットのCORS(Cross-Origin Resource Sharing)を設定します。CORSとは、S3とは違う他のドメインのサイトからS3上のリソースにアクセスするときの共有設定のことです。デフォルトではAllowedOriginが*のものに対して、GETメソッドのみ許可されているようです。それを以下のように変更します。

<CORSConfiguration>
    <CORSRule>
        <AllowedHeader>*</AllowedHeader>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>Authorization</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

※AllowedOriginを、特定のURL(例:http://www.example.com/)に限定すると、より権限を限定できて良いです。

FirefoxのプラグインのFirebugを使って、Console Logを見てみると、以下のようにコンテンツを取得できていることがわかりました。
f:id:kenjifunasaki:20131106131637p:plain

次に本記事のメインとなるS3 Uploadを試してみます。
以下のようなs3upload.htmlを作成しました。

<html>
<head>
<title>Sample</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<input type="file" id="file-chooser" />
<button id="upload-button">Upload to S3</button>
<div id="results"></div>

<script src="https://sdk.amazonaws.com/js/aws-sdk-2.0.0-rc1.min.js"></script>
<script type="text/javascript">
<!--

  AWS.config.update({accessKeyId: 'AKIAXXXXXXXXXXXXXX', secretAccessKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'});
  var bucket = new AWS.S3({params: {Bucket: 'BUCKET-NAME'}});

  var fileChooser = document.getElementById('file-chooser');
  var button = document.getElementById('upload-button');
  var results = document.getElementById('results');
  button.addEventListener('click', function() {
    var file = fileChooser.files[0];
    if (file) {
      results.innerHTML = '';

      var params = {Key: file.name, ContentType: file.type, Body: file};
      bucket.putObject(params, function (err, data) {
        results.innerHTML = err ? 'ERROR!' : 'UPLOADED.';
      });
    } else {
      results.innerHTML = 'Nothing to upload.';
    }
  }, false);
// -->
</script>
</body>
</html>

作成したs3upload.htmlを表示すると以下のような画面が表示されます。
f:id:kenjifunasaki:20131106163200p:plain
適当なテキストファイルを選択してアップロードすると、以下のように表示されます。
f:id:kenjifunasaki:20131106163224p:plain
S3 Management Consoleで確認すると、確かにアップロードされてました!
f:id:kenjifunasaki:20131106163249p:plain

あとは、JavaScript内にAWS Security Credential情報がベタ書きされてしまっているのを、以前書いた記事にあるようにSecurity Token Serviceを使って、一時的なTokenを使うようにすれば、権限を制限させることもできます。

以上ですー。