【入門者向け】Chat GPTに色々教えてもらいながらAWS S3にファイルをアップロードしてみる【3章: アップロード編】
記事の目的
- 初学者でもAmazon S3(以降S3)について理解を深められるようにする
- S3を使って画像をアップロードできるアプリケーションを作成できるようにする
関連記事
1章: バケット作成編
2章: アクセス許可の設定編
3章: アップロード編 ←今ここ
※この記事の内容は2章の続きからになります
注意事項
- AWSのコンソール画面は2023/9時点のものです
- Chat GPTの出力が必ずしも正しいとは限りませんのでビジネスで使う場合にはご注意ください。(当記事で登場しているAWSのアカウントは完全個人用になります)
1. ブラウザからアップロードするのはどうするのか?
早速聞いてみた。
2. バックエンド環境構築
聞いてみた
Chat GPTのコマンド実行前に今回実装するディレクトリを作っておきましょう(ディレクトリ名は適当でOKです)
mkdir s3-test
cd s3-test
今のディレクトリ位置。今後のコマンドは指定がない限りs3-test直下で実行するものとします
pwd
/Users/${自分のユーザー名}/s3-test
必要なものをインストール
npm init -y
npm install express --save
npm install multer aws-sdk --save
前回のChat GPT出力の「プロジェクトフォルダに、前回提供したサーバーサイドのコードを作成します。コードをapp.jsなどのファイルに保存できます。」に従ってファイル作成
touch app.js
前回のChat GPT出力のバックエンドコード
const express = require('express');
const multer = require('multer');
const AWS = require('aws-sdk');
const fs = require('fs');
const path = require('path');
const router = express.Router();
// AWS S3の設定
const s3 = new AWS.S3({
accessKeyId: 'YOUR_ACCESS_KEY_ID',
secretAccessKey: 'YOUR_SECRET_ACCESS_KEY'
});
// Multerの設定
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });
// ファイルアップロードのエンドポイント
router.post('/upload', upload.single('file'), (req, res) => {
const file = req.file;
if (!file) {
return res.status(400).json({ success: false, message: 'ファイルがありません。' });
}
const params = {
Bucket: 'YOUR_S3_BUCKET_NAME',
Key: `${Date.now()}_${file.originalname}`,
Body: file.buffer
};
s3.upload(params, (err, data) => {
if (err) {
console.error('S3アップロードエラー:', err);
return res.status(500).json({ success: false, message: 'アップロードエラーが発生しました。' });
}
console.log('S3アップロード成功:', data.Location);
return res.status(200).json({ success: true, message: 'アップロードが成功しました。' });
});
});
const app = express();
app.use('/', router);
const port = process.env.PORT || 3000;
app.listen(port, () => {
console.log(`サーバーがポート${port}で起動しました。`);
});
試しにサーバーを立ち上げてみましょう
node app.js
「サーバーがポート3000で起動しました。」が出れば成功です!
フロントエンド環境構築
フロントエンドの実装に入りましょう。ディレクトリ構成を教えてば的確なアドバイスが貰えると思うのでtreeコマンドで確認
tree -I 'node_modules'
では聞いてみましょう!
mkdir public
cd public
public % touch index.html
Chat GPT出力のフロントエンドコード
<!DOCTYPE html>
<html>
<head>
<title>画像アップロード</title>
</head>
<body>
<input type="file" id="fileInput">
<button onclick="uploadFile()">アップロード</button>
<script>
function uploadFile() {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
if (file) {
const formData = new FormData();
formData.append('file', file);
fetch('/upload', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('アップロードが成功しました!');
} else {
alert('アップロードが失敗しました。');
}
})
.catch(error => {
console.error('アップロードエラー:', error);
});
} else {
alert('ファイルを選択してください。');
}
}
</script>
</body>
</html>
/index.htmlで表示されるようにパスを追加
const app = express();
app.use('/', router);
app.use(express.static('public')); // 追加
s3-test直下でnode app.js
を実行している状態でhttp://localhost:3000/index.html にアクセス
4. AWSの環境変数の定義
あとは以下の部分を作成したAWSの値にすればいけると思います
// AWS S3の設定
const s3 = new AWS.S3({
accessKeyId: 'YOUR_ACCESS_KEY_ID',
secretAccessKey: 'YOUR_SECRET_ACCESS_KEY'
});
// 略
const params = {
Bucket: 'YOUR_S3_BUCKET_NAME',
Key: `${Date.now()}_${file.originalname}`,
Body: file.buffer
};
聞いてみた
アクセスキーの設定はIAMのユーザー詳細からできそうですね!
MJというユーザーは2章で作成したユーザーです
アクセスキー作成をクリックしたらなんか色んな選択肢があるやん🤔
聞いてみた。言葉通りローカルコードが良さそう
作成したアクセスキーを以下のコードから書き換える。
🚨Chat GPTが何度か警告している通り、アクセスキーとシークレットアクセスキーは公開リポジトリや公共の場所にコードを公開しないように注意してください🚨。
// チーム開発する時はenvなどで管理するかと思われます
const s3 = new AWS.S3({
accessKeyId: 'YOUR_ACCESS_KEY_ID', // ここ
secretAccessKey: 'YOUR_SECRET_ACCESS_KEY' // ここ
});
バケット名は1章で作成したバケット名を入力。
バケット名も公開リポジトリや公共の場所にコードに無闇に公開しないように注意してください
// チーム開発する時はenvなどで管理するかと思われます
const params = {
Bucket: 'YOUR_S3_BUCKET_NAME', // ここ
Key: `${Date.now()}_${file.originalname}`,
Body: file.buffer
};
5. アップロードしてみる
適当が画像を用意してアップロードしてみる。
なんかエラー出てますね💦
聞いてみた
どうやらCORSが原因ぽいですね(S3と関係ない範囲なので詳しい理由の調査は省略します)
fetch('/upload', {
method: 'POST',
body: formData,
mode: 'cors' // 追加
})
再度アップロード。いけたっぽいですね!
バケット詳細ページのダウンロードしてみましょう!
(日本語名だけ文字化けする可能性があるので英語にしました)
画像をダウンロードできました!
次回はブラウザから画像をダウンロードできるようにする実装を行う予定です!
Discussion