LoginSignup
22
23

More than 5 years have passed since last update.

Lambdaを使ってindex.htmlを自動生成する

Last updated at Posted at 2014-12-14

はじめに

Lambdaでは、Amazon S3にコンテンツがPUTされると、コードを実行することができます。
そこで、S3にファイルがPUTされたら、そのバケットにあるコンテンツの一覧を表示する「index.html」を自動生成してみたいと思います。
動作結果は、下の図のとおり。S3においてあるコンテンツの内容が一覧表示される、簡易なコンテンツ共有サイトを簡単に実現できます。ファイル一式を友人に渡す時に便利ですね。ファイルのLinkは、署名付きURLにして期間限定公開にすることや、AWSのマネージメントコンソールで「make public」されたのと同じ状態で、期間限定なしでダウロード可能な状態にすることもできます。

余談ですが、この「make public」ってメニュー項目の響きが好きです。これで、世の中に公開されるんだな、という感じです。「Work smart, Have fun, Make public」という感じです。

result001a.png

Lambdaコード

このlambdaコードは、Oregonリージョンで動かします。

LambdaFunctionCode
console.log('Loading event');
var AWS = require('aws-sdk');
var s3 = new AWS.S3();
var regionurl = 'https://s3-us-west-2.amazonaws.com/';

exports.handler = function(event, context) {

    var htmlheader = '<html><haed><link href="test.css" type="text/css" rel="stylesheet" /></head><body><table class="sample007"><tr><th>No.</th><th>Contents</th><th></th><th>Date</th></tr>';
    // index.html header

    var htmlfooter = '</table></body></html>';
    // index.html footer

    var indexhtmlbucket = 'yoicht-makepublic';  // bucket of Static web hosting
    var htmlfilename = 'index.html';            // filename of index document
    var maxkeys = 100;                          // max keys

    var bucketname = event.Records[0].s3.bucket.name;
    var bucketkey  = event.Records[0].s3.object.key;

    console.log('Bucket = ' + bucketname);
    console.log('key = ' + bucketkey);

    var param = {
        Bucket: bucketname,
        Key: bucketkey,
        ACL: 'public-read'      // If signed-url, write 'private'.
    };
    s3.putObjectAcl(param, function(err, data) {
        if (err)
            console.log(err, err.stack);
        else
            makeTable(bucketname, htmlheader, htmlfooter, indexhtmlbucket, htmlfilename, maxkeys, param.ACL );
    });   
};

function makeTable(bucketname, htmlheader, htmlfooter, indexhtmlbucket, htmlfilename, maxkeys, acl ) {
    var params = {Bucket: bucketname, EncodingType: 'url', MaxKeys: maxkeys};
    var url ='';

    s3.listObjects(params, function(err, data) {
        if (err) {
            console.log(err, err.stack);
        } else {
            var indexhtml = htmlheader;

            for(var index in data.Contents) {
                if (acl == 'public-read') {
                    url = regionurl + bucketname + '/' + data.Contents[index].Key;   // for make public
                } else {
                    params = {Bucket: bucketname, Key: data.Contents[index].Key, Expires: 36000};
                    url = s3.getSignedUrl('getObject', params);
                }

                indexhtml += '<tr><td align="center">'+ index + '</td>' + 
                '<td><a href="' + url + '">' + data.Contents[index].Key + '</a></td>' +
                '<td><img src="' + url + '" height="50">' + '</td>' +  
                '<td>' + data.Contents[index].LastModified + '</td>' + 
                '</tr>';
            }
            indexhtml += htmlfooter;

            params = {
                Bucket: indexhtmlbucket,
                Key: htmlfilename,
                ACL: 'public-read',
                Body: indexhtml,
                ContentType: 'text/html'
            };
            s3.putObject(params, function(err, data) {
                if (err)
                    console.log(err, err.stack);
                else
                    console.log(data);
            });
        }
    });
    console.log(indexhtml);
    context.done(null, "done");
}

var param = {
  Bucket: backetname,
  Key: backetkey,
  ACL: 'public-read'
};

で、ACL : 'private'と書けば、アクセス期間を限定可能なsigned-urlになります。

注意点が2つあります。
ひとつめは、「index.html」を生成するバケット(「indexhtmlbucket」)は、コンテンツをPUTするバケットとは別にしておく必要があります。このコードを流用される場合は、ご自分のBucketに変更する必要があります。また、Bucketは、Static Web Hostingの設定をしておく必要があります。
ふたつめは、Lambdaの「Change function configuration and role」の設定で、S3の権限設定を変える必要があります。デフォルトのRoleで設定されているのは、S3の読み込みと書き込み権限だけです。

Role
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:*"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:*"
      ],
      "Resource": [
        "arn:aws:s3:::*"
      ]
    }
  ]
}

動作の概要

  1. S3 PUTをトリガーに、Lambaのコードが実行開始。
  2. S3 PUTされたコンテンツのバケット名とkeyを取得。
  3. S3 PUTされたコンテンツのアクセス権を設定(public-read or private)。
  4. バケット内のコンテンツの一覧を取得。
  5. tableタグでコンテンツ一覧を整形。
  6. index.htmlを作成し、static web hostingの設定がしてある別のバケットにPUT。
  7. おしまい。

さいごに

このコードは、改良の余地が多くあります。まず、削除が反映されません。これは、Lambdaで削除イベントのきっかけをつかめないためです。あと、処理をサボっているので、日本語のコンテンツに対応できていないなどがあります。
そのほか、S3 PUTをきっかけに、コンテンツのサムネイルを自動生成したり、署名付きURLのダウンロードできる期間もあわせて表示したり、styleシートを読み込み見た目リッチなhtmlにする、など思いつきました。

Lambdaを使うのは初めてでしたが、簡単ですね。Lambdaを使うと、S3のstatic web hostingも、「static」が取れてしまいます。便利!。

この記事は、私の所属している組織とは何の関係もありません。

22
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
23