LoginSignup
12
12

More than 5 years have passed since last update.

S3に置いたファイルのContent-TypeをLambdaで変更する

Last updated at Posted at 2015-07-02

もともとこのようなことを行う必要性が生まれたのは、

Office2007以降の形式(.xlsx, .docx, .pptx)のファイルをブラウザからS3にアップした際に、
Content-Typeの自動設定が行われると、
application/vnd.ms-excel」(Excelの場合)
と設定されます。

これはOffice2003以前の形式(.xls, .doc, .ppt)のContent-Typeであるため、
ブラウザで対象ファイルをダウンロードすると、
.xlsx」だったファイルの拡張子が、「.xls」となってダウンロードされてしまうという事象が起こるのです。(Excelの場合)

これを防ぐためにLambdaを利用してContent-Typeを変更してしまおうということで、以下コード。

node.js
console.log('Loading event');
var aws = require('aws-sdk');
var s3 = new aws.S3({apiVersion: '2006-03-01'});
var s3tokyo = new aws.S3({apiVersion: '2006-03-01', endpoint: 'https://s3-ap-northeast-1.amazonaws.com'});

exports.handler = function(event, context) {
   console.log('Received event:');
   console.log(JSON.stringify(event, null, '  '));
   // Get the object from the event and show its content type
   var bucket = event.Records[0].s3.bucket.name;
   var key = decodeURIComponent(event.Records[0].s3.object.key);
   s3tokyo.getObject({Bucket:bucket, Key:key},
      function(err,data) {
        if (err) {
           console.log('error getting object ' + key + ' from bucket ' + bucket );
           context.done('error','error getting file' + String(err));
        }
        else {
            console.log('logging Content-Type : ',data.ContentType);
            if  ((data.ContentType != "application/vnd.ms-excel")&&
                (data.ContentType != "application/msword")&&
                (data.ContentType != "application/vnd.ms-powerpoint")){
                console.log('Content Type not MS-Office file.');
                context.done(null,'skip execution.');
            }
            else {
               var type = "binary/octet-stream";
               var params = {
                  Bucket: bucket, 
                  CopySource: bucket + "/" + encodeURIComponent(key),
                  Key: key, 
                  ContentType: type,
                  MetadataDirective: "REPLACE"
                };
                console.log('replace object.');
                console.log('bucket : ' + bucket);
                console.log('CopySource : ' + bucket + "/" + key);
                s3tokyo.copyObject(params, function(err2, data2){
                    if (err2){
                       context.done('error','error2 getting file '+ String(err2));
                    }else{
                        console.log('replace done! Content-Type : ',data2.ContentType);
                        context.done(null,'object meta-data changed.');
                    }
                });
            }
        }
        }
    );
};

マルチバイト文字のKey名への対応

2バイト文字のファイル名の場合にうまくいかなかったのですが、
S3内ではURIエンコードされているので、

getObjectの際はdecodeURIComponent(key)
putObjectの際はencodeURIComponent(key)

することで解決できます。

イベントソースの設定

以下2つのイベントを対象バケットに設定します。
・ Put
・ CompleteMultiPartUpload
AWSマネージメントコンソール、API、CLIいずれによっても、ファイルサイズによってMultiPart Uploadに自動的に切り替わりますので、CompleteMultiPartUploadも有効にしておくことが必要です。

※Copyイベントの設定は厳禁です。これを設定すると、コード内でのCopy処理によってループしてしまうかも。

12
12
6

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
12
12