Amazon S3 の署名付き URL を使ってファイルをダウンロードする Node.js コード
Amazon S3 の、既に出尽くしている話。非公開の S3 バケットでも、署名付き URL というのを作ってやれば、URL の生成から15分間限定で対象のオブジェクトをインターネット経由で普通にダウンロードできる。
サーバサイド (Node.js) のコードは次のとおり。
# バージョン 2.1295.0 で検証
$ npm install --save aws-sdk
@aws-sdk/client-s3
という別のクライアントライブラリもあるのだが、今回は aws-sdk
パッケージを使用している。
const AWS = require('aws-sdk');
AWS.config.update({
accessKeyId: '【アクセスキーID】',
secretAccessKey: '【シークレットアクセスキー】',
region: 'ap-northeast-1'
});
const getSignedUrl = async () => {
const s3 = new AWS.S3();
const params = { Bucket: '【バケット名】', Key: '【オブジェクト名】.txt' };
try {
await s3.headObject(params).promise();
}
catch(error) {
if(error.code === 'NotFound') console.log('そんなファイルないよ');
return;
}
// `params` で `Expires` (秒) プロパティを未指定だと15分間の制限となる
try {
const url = await new Promise((resolve, reject) => {
s3.getSignedUrl('getObject', params, (error, url) => {
if(error) return reject(error);
resolve(url);
});
});
console.log('The URL is :', url);
return url;
}
catch(error) {
console.log(error);
}
};
AWS.S3
の headObject()
でファイルの存在がチェックできる。この API は Promise 形式にも対応しているので .promise()
を await
している。
実際に署名付き URL を発行するのは getSignedUrl()
部分。この API はコールバック形式でしか返してくれないので自前で Promise 化している。
コレで長ったらしい「署名付き URL」が生成できるので、フロントエンドでよしなにダウンロードさせてやれば良い。
// 上述のバックエンド API を呼び出して署名付き URL を取得したテイ
const response = await window.fetch('/get-signed-url');
const { url } = await response.json();
// クリックイベントを発火させてファイルをダウンロードさせる
const downloadLink = document.createElement('a');
downloadLink.href = url; // 署名付き URL を設定する
downloadLink.download = 'example.txt'; // ファイル名
downloadLink.click();
以上。