⛈️

【入門者向け】Chat GPTに色々教えてもらいながらAWS S3にファイルをアップロードしてみる【3章: アップロード編】

2023/09/16に公開

記事の目的

  • 初学者でもAmazon S3(以降S3)について理解を深められるようにする
  • S3を使って画像をアップロードできるアプリケーションを作成できるようにする

関連記事
1章: バケット作成編
2章: アクセス許可の設定編
3章: アップロード編 ←今ここ

※この記事の内容は2章の続きからになります

注意事項

  • AWSのコンソール画面は2023/9時点のものです
  • Chat GPTの出力が必ずしも正しいとは限りませんのでビジネスで使う場合にはご注意ください。(当記事で登場しているAWSのアカウントは完全個人用になります)

1. ブラウザからアップロードするのはどうするのか?

早速聞いてみた。
スクリーンショット 2023-09-16 7.28.04.png
スクリーンショット 2023-09-16 7.28.35.png
スクリーンショット 2023-09-16 7.28.45.png

2. バックエンド環境構築

聞いてみた
スクリーンショット 2023-09-16 7.40.56.png
スクリーンショット 2023-09-16 7.41.21.png

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'

では聞いてみましょう!
スクリーンショット 2023-09-16 8.02.50.png
スクリーンショット 2023-09-16 8.03.21.png

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 にアクセス
スクリーンショット 2023-09-16 8.19.30.png

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
};

聞いてみた
スクリーンショット 2023-09-16 8.23.44.png
スクリーンショット 2023-09-16 8.24.02.png

アクセスキーの設定はIAMのユーザー詳細からできそうですね!
MJというユーザーは2章で作成したユーザーです
スクリーンショット 2023-09-16 8.26.32.png
スクリーンショット 2023-09-16 8.26.44.png

アクセスキー作成をクリックしたらなんか色んな選択肢があるやん🤔
スクリーンショット 2023-09-16 8.30.44.png

聞いてみた。言葉通りローカルコードが良さそう
スクリーンショット 2023-09-16 8.33.46.png

スクリーンショット 2023-09-16 8.34.39.png

作成したアクセスキーを以下のコードから書き換える。
🚨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. アップロードしてみる

適当が画像を用意してアップロードしてみる。
なんかエラー出てますね💦
スクリーンショット 2023-09-16 8.49.27.png

聞いてみた
スクリーンショット 2023-09-16 8.54.37.png
スクリーンショット 2023-09-16 8.54.24.png

どうやらCORSが原因ぽいですね(S3と関係ない範囲なので詳しい理由の調査は省略します)

fetch('/upload', {
  method: 'POST',
  body: formData,
  mode: 'cors' // 追加
})

再度アップロード。いけたっぽいですね!
スクリーンショット 2023-09-16 9.09.03.png

バケット詳細ページのダウンロードしてみましょう!
(日本語名だけ文字化けする可能性があるので英語にしました)
スクリーンショット 2023-09-16 9.09.33.png

画像をダウンロードできました!
スクリーンショット 2023-09-16 9.10.29.png

次回はブラウザから画像をダウンロードできるようにする実装を行う予定です!

Discussion