⛅
フロントから直接S3にファイルをアップロードする
こんにちは、ハトです。いままでサーバーを通じでS3にアップロードさせてたのですが、直接アップロードさせたほうが、作りやすいことに気づいて移行しました。以下知見の共有です。
流れ
STEP:
- ブラウザからファイルをアップロード。ファイルのtypeとnameをバックエンドに送信。
- バックエンドはS3のsdkをもとに署名付きURLをS3サービスにリクエストする。このときBucket名やファイル名(Key)とファイルタイプをパラメータとして送る
- バックエンドはsdkから署名付きURLを受け取り、フロントエンドにわたす
- フロントエンドはもらったURLに直接ファイルをPUTする。
フロントエンドのコード
ファイルを何らかの方法で取得した前提です(inputタグからとか)。
// step1: 署名付きurlを取得
const resSignedUrl = await axios.get(`/upload`,
{
fileName: file.name,
fileType: file.type
}
);
// step4:
const res = await axios.put(
resSignedUrl.data.url,
file,
{
headers: {
'Content-Type': file.type,
},
}
);
バックエンドのコード
nodejs。予めS3のバケットを公開設定にしておいてください。
またフロントからアップロードする際にはS3のバケットにCORS設定が必要になるかもしれません。
EC2上で動かす場合、IAMロールなどでS3に署名付きURLを要求できる権限が必要です。
showPresignedUrl: (req, res, next) => {
// NOTE: signatureVersion: 'v4'にしないと403forbiddenエラーになる。
const s3 = new AWS.S3({ signatureVersion: 'v4' });
const params = {
Bucket: process.env.S3_BUCKET_NAME, // 環境変数に公開設定されたS3のバケット名を指定しておく。
Key: req.query.fileName,
Expires: 60,
ContentType: req.query.fileType,
};
// step3: SDKを通じて署名付きurlを取得する。
s3.getSignedUrl('putObject', params, (err, url) => {
if (err) {
next(err)
return;
}
// step4: フロントに返す。
res.json({
url,
})
return;
});
}
Discussion