Lambda(Node.js)からS3のファイルにアクセスする連携方法
Lambda(Node.js)からS3のファイルにアクセスする方法です。
S3とは単なるファイルストレージです。ウィンドウズのエクスプローラと同じでC:\a\b\cみたいな構造でファイルなどを置くことができます。
S3にバケットを作成します。Cドライブみたいなものとイメージして差し支えないと思います。
「バケットを作成する」をクリックします。
ここでは、「sde」というバケットを作成しました。
sdeにアクセスすると、フォルダの作成ができますので作成してみます。
ここでは「a」というフォルダを作成しました。さらにa/b/cというようにフォルダを作成します。
これで、sdeというバケットにa/b/cというフォルダ構造を作成することができました。
この配下にJSONオブジェクトが定義してある.jsonファイルを配置してみます。
「アップロード」をクリックします。
ローカルにあるファイルをこのウィンドウにドラッグアンドドロップします。
ファイルを置くと上記のようになるので「次へ」をクリックします。
そのまま「次へ」をクリックします。
「次へ」をクリックします。
「アップロード」をクリックします。
これで、sdeというバケットのa/b/cフォルダ配下にsample.jsonをアップロードすることができました。
次はlambdaからs3ファイルへアクセスする例です。ファイル一覧を取得するにはlistObjectsV2メソッドを使います。
const AWS = require('aws-sdk'); const s3 = new AWS.S3({'region':'ap-northeast-1'}); exports.handler = (event, context, callback) => { let params = { 'Bucket': 'sde', 'Prefix': 'a/b/c' } s3.listObjectsV2(params, function(err, data) { data.Contents.forEach(function(elem){ console.log(elem.Key); }); response = data.Contents; callback(null, response); }); };
バケットsdeの/a/b/c/配下のjsonファイルだけ取得できると思ったのですが、フォルダが取れて、さらにそのフォルダ内のファイルが取れてきてしまいます。
[ { "Key": "a/b/c/", "LastModified": "2017-12-03T00:06:15.000Z", "ETag": "\"d41d8cd98f00b204e9432298ecf8427e\"", "Size": 0, "StorageClass": "STANDARD" }, { "Key": "a/b/c/sample.json", "LastModified": "2017-12-03T00:19:39.000Z", "ETag": "\"593902c4008cdb4c567342badee01680\"", "Size": 41, "StorageClass": "STANDARD" } ]
フォルダ配下のファイルだけ取得したい場合はStartAfterを指定する
Contents.Keyにフォルダが取れてきてしまうわけですが不要だ、という場合はStartAfterを指定します。StartAfterはAWS S3はこの指定されたキーの後のリストを取得します。
const AWS = require('aws-sdk'); const S3 = new AWS.S3({'region':'us-east-1'}); exports.handler = (event, context, callback) => { let params = { 'Bucket': 'sde', 'Prefix': 'a/b/c/', 'StartAfter':'a/b/c/' // a/b/c/配下だけを取得する } S3.listObjectsV2(params, function(err, data) { data.Contents.forEach(function(elem){ console.log(elem.Key); }); response = data.Contents; callback(null, response); }); };
結果は以下のようにファイルのフルパスのみ取得されます。(これでも問題があります)
[ { "Key": "a/b/c/sample.json", "LastModified": "2017-12-03T00:19:39.000Z", "ETag": "\"593902c4008cdb4c200892badee01680\"", "Size": 41, "StorageClass": "STANDARD" } ]
マネジメントコンソールからフォルダを作成しない(結論)
StartAfterを指定してもその配下にフォルダが存在する場合は、a/b/c/d
というようなフォルダが取得されてしまいます。これはフォルダは0バイトのオブジェクトだからです。
プログラムや、CLIのcpなどでファイルをアップロードすれば0バイトのフォルダはそもそも作成されないので、CLIでファイルをアップロードすれば解決します。
もしマネジメントコンソールからフォルダを作成してしまった場合は、フォルダ=オブジェクトなのでrmコマンドで削除すればよいです。
バケットは以下の全フォルダ(オブジェクト)を削除するコマンド例です。
aws s3 rm s3://バケット名/ --exclude '*.*' --recursive
間違って全オブジェクトが来得てしまって困る場合などは、最後に--dryrun
オプションをつけて確認してから実行すればよいです。
listObjectsV2で取得できるオブジェクトは最大1000件
listObjectsV2で取得できるオブジェクトは最大1000件です。1000件以上オブジェクトが存在する場合は、NextContinuationTokenにトークンが設定されます。IsTruncated=trueとなります。
次の1000件を取得する場合にlistObjectsV2の引数にContinuationToken: トークン
を指定します。最後の1000件になった場合にIsTruncated=falseとなります。
1000件はデフォルト値(最大値)なので、listObjectsV2の引数にMaxKeys: 100
などして1回で取得する最大件数を変更することができます。但し、1001以上の値を指定しても最大1000件となります。
AWS-SDKのs3.putObjectメソッドでファイルをアップロードする(node.js v12.x)
s3にはputObjectメソッドがあり、このメソッドを使ってS3バケットの指定したオブジェクトキーでファイルをアップロードすることができます。
const AWS = require('aws-sdk'); const s3 = new AWS.S3({'region':'ap-southeast-1'}); AWS.config.update({region: 'ap-southeast-1'}); exports.handler = async (event) => { const params = { Bucket:'test-bucket', Key:'dir1/subdir1/sample.json', Body: JSON.stringify({name: 'takahashi', age: 50},undefined,1), ContentType: 'application/json' } const json = await s3.putObject(params).promise().catch(err=>{ throw new Error(`エラー`) }) }
今回はJSONファイルなので、ContentType: 'application/json'
としています。
Bucketにバケット名、Keyにオブジェクトキー名を指定します。
sample.jsonの中身は、Bodyで指定します。この時、文字列にしないといけません。(JSONファイルの場合)
その為、JSON.stringifyをしていますが、オブジェクトとして整形するために、第二引数、第三引数を指定してあげます。
引数 | 値 |
---|---|
第一 | オブジェクト |
第二 | undefined |
第三 | 1 |
これでS3にアップロードされたファイルがオブジェクト形式になっていることが確認できます。
これは見た目上の問題であって、s3のgetObjectで取得する際はJSON.parse(file.Body)
としてあげないといけません。
0バイトのファイルをputする
0バイトのファイルをputObjectで作成する場合は、Bodyプロパティの値をnullにすれば0バイトのファイルをputすることが出来ます。””とすると2Byteのファイルが出来てしまいます。
const AWS = require('aws-sdk'); const S3 = new AWS.S3({'region':'us-east-1'}); exports.handler = async (event) => { const param = { 'Bucket': 'bucketname', 'Key': 'var/tmp/a.json', 'Body': null // nullにしておく } await S3.putObject(param).promise() }
AWS-SDKのs3.deleteObjectメソッドで存在しないファイルを削除してもエラーにならない(node.js v12.x)
getObjectなどでファイルが存在しない場合、エラーとなりますが、deleteObjectメソッドで存在しないファイルを削除してもエラーにはならないようです。
以下、実行例です。await – catchのcatchには入りません。
const AWS = require('aws-sdk'); const s3 = new AWS.S3({'region':'ap-southeast-1'}); AWS.config.update({region: 'ap-southeast-1'}); exports.handler = async (event) => { const deletes = await s3.deleteObject( { Bucket:'test-bucket', // 存在するバケット Key:'test/sample.json' // 存在しないファイル }).promise().catch(err=>{ throw new Error(err) // test/sample.jsonが存在しなくてもcatch句には入らない }) }
deleteObjectメソッドでは存在しないバケットを指定した場合にはcatch句に入ります。
const AWS = require('aws-sdk'); const s3 = new AWS.S3({'region':'ap-southeast-1'}); AWS.config.update({region: 'ap-southeast-1'}); exports.handler = async (event) => { const deletes = await s3.deleteObject( { Bucket:'test-bucketxxx', // 存在しないバケット Key:'test/sample.json' }).promise().catch(err=>{ throw new Error(err) // catch句に入る }) }
KHI入社して退社。今はCONFRAGEで正社員です。関西で140-170/80~120万から受け付けております^^
得意技はJS(ES6),Java,AWSの大体のリソースです
コメントはやさしくお願いいたします^^
座右の銘は、「狭き門より入れ」「願わくは、我に七難八苦を与えたまえ」です^^
コメント