JavaScript
AWS
S3
クラウド
React

AWS+Reactアプリ作成入門(S3編)

AWS+Reactアプリ作成入門(Cognito編)
AWS+Reactアプリ作成入門(S3編)
AWS+Reactアプリ作成入門(DynamoDB編)
AWS+Reactアプリ作成入門(IAM Role編)
AWS+Reactアプリ作成入門(ログイン後のAdmin編)

今回作成したアプリ ==>久喜SNS

 前回はユーザ認証(Cognito)周りを中心に述べましたが、今回はS3の利用について述べたいと思います。S3は2つの目的で使います。画像の保存とReactアプリの保存です。Reactアプリの開発時は別サーバで行い、完成したらS3にdeployします。

 まずAWSコンソールでS3にバケットを作成します。Reactアプリを走らせますので静的ホスティングをONにします。プログラムをdeployした時に誰でもアクセスできるように、以下のようにバケットポリシーを設定します。これで誰でもRead Onlyでプログラムにアクセスでき、ホスティングのページに示されたURLにアクセスするとプログラムが起動されます。Cognitoでプログラムの実行に権限を与えることはできますが、バケットポリシーはプログラムの実行以前の、プログラムのロードに必要となります。プログラムから画像をアップロードしたり削除したりするCognitoの権限(Role)については別の機会にしまします。

バケットポリシー
{
  "Version":"2012-10-17",
  "Statement":[
    {
      "Sid":"AddPerm",
      "Effect":"Allow",
      "Principal": "*",
      "Action":["s3:GetObject"],
      "Resource":["arn:aws:s3:::examplebucket/*"]
    }
  ]
}

公式サイト:Granting Read-Only Permission to an Anonymous User

 Cognitoは面倒でしたが、S3はシンプルです。信頼性が高く低価格なので、認証が不要であれば、簡単にReactアプリを作成し、以下のコマンド一発でdeployすることが可能です。react-create-appで作成したプロジェクトのディレクトリーで実行します。この辺がMeteorにない魅力ですね。

npm run build && aws s3 sync build/ s3://バケット名

 このコマンドを使うためには予めaws-cliを設定しておく必要があります。ついでですのでその手順を載せておきます。

1.AWS-CLIのインストール

 公式サイト「AWS CLI のインストールと設定」に従って行います。
http://docs.aws.amazon.com/ja_jp/streams/latest/dev/kinesis-tutorial-cli-installation.html

(1)インストール
 次のコマンドでインストールできます。

curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
sudo python get-pip.py
sudo pip install awscli
aws help

(2)設定
 まずAWSコンソールのIAM画面のユーザで自分を検索し、アクセスキーとシークレットキーの入手します。認証情報タブでアクセスキーの作成をクリックするとポップアップにシークレッドキーが表示されますので、忘れずにコピーしておいてください。

aws configure
AWS Access Key ID [None]: AKIAXXXXXXXXXXXXXX
AWS Secret Access Key [None]: XXXXXXXXXXXXXXXXXXX
Default region name [None]: ap-northeast-1
Default output format [None]: json

(3)確認
 念のため確認しておきます。これでaws-cliが使えるようになりました。

$ cat ~/.aws/credentials
[default]
aws_access_key_id = AKIAXXXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXXXX

$ cat ~/.aws/config
[default]
output = json
region = ap-northeast-1

2.画像のアップロード

 ReactアプリからS3にアクセスするためには権限が必要となります。権限は非ログインユーザとログインユーザにそれぞれ付与されます。そのためにはCognitoの設定が必要となりますが、これについては前回述べましたので参照してください。

 まずファイル選択ですが以下のJSXで行います

ファイル選択ボタン
<input type="file" onChange={this.handleFileChange.bind(this)}/>

 this.state.fileに選択したファイルを保存します。e.target.files[0]で選択したファイルにアクセスできます。

ファイル選択ハンドラー
  handleFileChange(e) {
    this.setState({file: e.target.files[0]});
  }

 送信ボタンを押された時のハンドラーの一部です。通常callbackの中で処理を行いますので、予め _self=this としていると仮定してください。s3.putObject()で画像ファイルをアップロードしています。一応 Metadata も設定していますが、今回は使っていないので不要です。

送信ボタンのハンドラの一部
        if (!_self.state.file.name.match(/^[0-9a-zA-Z\.\_\-]*$/)) {
            handleErrorFunc('エラー:ファイル名は小文字の英数字と . - _ しか使えません: '+_self.state.file.name );
            return;
        }
        filename = 'contents/images/'+identityId+'/'+_self.state.file.name;
        fileType = _self.state.file.type;
        var params = {
            Bucket: bucketname,
            Key: filename,
            ContentType: _self.state.file.type,
            Body: _self.state.file,
            Metadata: {
              data: JSON.stringify({
                identityId: identityId,
                uploadTime: uploadTime,
                uploadDate: uploadDate
              })
            }
        };
        var s3 = new AWS.S3();
        s3.putObject(params, function(err, data) {
            if(err) {
                console.log("Err: upload failed :" +err);
            } else {
                console.log("Success: upload ok");
            }
        });

3.画像の参照

 上で作成したfilename変数を使えば、画像は以下のURLで参照できます。実際はfilenameはDynamoDBのテーブルに保存してあるので、そこから取り出してURLを作成することになります。

const imgurl = 'http://'+bucketname+'.s3-'+appConfig.region+'.amazonaws.com/'+filename;

4.画像の削除

 画像の削除も簡単です

削除ボタンのハンドラの一部
        const s3 = new AWS.S3();
        const params1 = {
            Bucket: bucketname,
            Key: item.filename,
        };
        s3.deleteObject(params1, function(err, data) {
          if (err) console.log(err); // an error occurred
          else     console.log("### delete image ok");           // successful response
        });

5.キャッシュファイル

 DynamoDBは課金制ですし、安いスループットに設定しているので、トップページにキャッシュを設けることにしました。これは3番目のS3の使い方になります。

 トップページは常に現在の投稿の一覧を取得し表示してますので、DyanmoDBにqueryを発行しています。この投稿の一覧をJSONファイルとしてS3にキャッシュします。新たな投稿や編集があった場合にキャッシュを削除します。

キャッシュファイルの作成
    var params = {
        Bucket: bucketname,
        Key: cachepath,
        ContentType: 'application/json',
        Body: JSON.stringify(data.Items)
    };
    s3.putObject(params, function(err, data) {
      if (err) console.log("### cache upload error",err, err.stack);
      else     console.log("### cache upload successful"+data);
    });

キャッシュの削除や参照については割愛します。

今回はこれで終わりますが、DynamoDBなどは次回以降に書いていきたいと思います。