🖼️

FireStorageのためにBlazeプランにするのが嫌なあなたへ~画像保存サーバーを作って解決しよう~

に公開

Firebase の Storage 使えなくね?

何年か前は無料プランでも使えた記憶があったけれど、無料プランの範囲の変更があったのか、Spark プランでは利用できなくなっていた(今更)。私自身まだ学生であり、クレジットカードを登録できない!(デビットとか作ればいけるかもしれないけれどめんどくさい)

ならば画像保存用のサーバー立てればいいじゃない!

という気持ちで画像保存用のサーバーを構築する方法を解説します。

必要なもの

  • 自分の持っているサーバー: Node.js が実行できる環境
  • テキストエディタ: VSCode など

テキストエディタはサーバーと SSH 接続して記述できる VSCode をおすすめします(SSH 接続の方法については解説しないので別途調べてください)

サーバーのセットアップ

ここから、本格的にサーバーをセットアップしていきます

ステップ 1:プロジェクトの初期化

まず、プロジェクト用のディレクトリを作成し、その中で npm を初期化します。

# プロジェクト用ディレクトリを作成して移動
mkdir image-uploader
cd image-uploader

# npmプロジェクトを初期化
npm init -y

ステップ 2:必要なライブラリのインストール

サーバーの構築に必要なライブラリをインストールします

  • express:Web サーバーのフレームワーク
  • multer:ファイルアップロード処理を簡単にするためのライブラリ
  • cors:オリジン間のリソース管理(CORS)を許可するためのライブラリ

以下のコマンドを打ち込んでインストールしてください。

npm install express multer cors

ステップ 3:サーバーコードの作成(server.js)

プロジェクトのルート(image-uploader)にserver.jsというファイルを作成し、以下のコードを入力してください。

// server.js

// 1. 必要なモジュールを読み込む
const express = require("express");
const multer = require("multer");
const path = require("path");
const cors = require("cors");
const crypto = require("crypto");

// 2. Expressアプリを初期化
const app = express();
const port = 3000;

// 3. CORSミドルウェアを使用
// これにより、異なるドメインのフロントエンドからのリクエストを許可します。
app.use(cors());

// 4. ファイルの保存場所とファイル名を定義
const storage = multer.diskStorage({
	// 保存先のディレクトリを指定
	destination: (req, file, cb) => {
		cb(null, "uploads/");
	},
	// ファイル名を定義
	filename: (req, file, cb) => {
		// 元のファイル名から拡張子を取得
		const ext = path.extname(file.originalname);
		// ランダムな文字列を生成してファイル名とする(ファイル名の衝突と文字化けを防ぐ)
		const randomName = crypto.randomBytes(16).toString("hex");
		cb(null, randomName + ext);
	},
});

// 5. Multerの設定
const upload = multer({ storage: storage });

// 6. 静的ファイル配信の設定
// 'uploads'ディレクトリ内のファイルをURLから直接アクセスできるようにします。
app.use("/uploads", express.static(path.join(__dirname, "uploads")));

// 7. 画像アップロード用APIエンドポイントの作成
// POST /upload というURLで、'image'という名前のファイルを1つ受け取ります。
app.post("/upload", upload.single("image"), (req, res) => {
	// ファイルがアップロードされなかった場合のエラーハンドリング
	if (!req.file) {
		return res.status(400).send({ message: "ファイルが選択されていません。" });
	}

	// 成功した場合、アップロードされた画像のURLをクライアントに返す
	const imageUrl = `${req.protocol}://${req.get("host")}/uploads/${
		req.file.filename
	}`;
	res.status(200).send({ imageUrl: imageUrl });
});

// 8. サーバーを起動
app.listen(port, () => {
	console.log(
		`サーバーがポート${port}で起動しました。 http://localhost:${port}`
	);
});

まだ保存用のuploadsディレクトリを作成していないのでそのディレクトリを作成します。

mkdir uploads

ステップ 4:アップロードテスト用の HTML ファイル作成

テスト用に、一度画像を選択して、アップロードするための簡単な HTML ファイルを作成します。自分の PC に以下のindex.htmlを保存してください。

<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta charset="UTF-8" />
		<title>画像アップロード テスト</title>
	</head>
	<body>
		<h1>画像をサーバーにアップロード</h1>
		<input type="file" id="imageInput" accept="image/*" />
		<button onclick="uploadImage()">アップロード</button>

		<div id="result"></div>

		<script>
			// サーバーのURL(IPアドレスとポート)をここに設定
			const SERVER_URL = "http://yourAddress/upload";

			async function uploadImage() {
				const imageInput = document.getElementById("imageInput");
				const file = imageInput.files[0];
				const resultDiv = document.getElementById("result");

				if (!file) {
					resultDiv.innerText = "ファイルが選択されていません。";
					return;
				}

				const formData = new FormData();
				formData.append("image", file); // サーバー側の`upload.single('image')`と名前を合わせる

				try {
					const response = await fetch(SERVER_URL, {
						method: "POST",
						body: formData,
					});

					if (response.ok) {
						const data = await response.json();
						resultDiv.innerHTML = `
                        <p>アップロード成功!</p>
                        <p>画像URL: <a href="${data.imageUrl}" target="_blank">${data.imageUrl}</a></p>
                        <img src="${data.imageUrl}" alt="アップロードされた画像" width="300">
                    `;
					} else {
						resultDiv.innerText =
							"アップロードに失敗しました。サーバーからの応答: " +
							response.status;
					}
				} catch (error) {
					console.error("通信エラー:", error);
					resultDiv.innerText =
						"サーバーとの通信に失敗しました。詳細はコンソールを確認してください。";
				}
			}
		</script>
	</body>
</html>

yourAddressのところは自分のサーバーのアドレスを入力してください。

ステップ 5:アップロードテスト

実際にアップロードのテストを行います。
サーバー上で以下のコマンドを入力し、簡単な動作確認を行います。

node server.js

これで自分の PC 上で先ほど作成した index.html を開いて、みて画像ファイルを選択して選択したファイルがプレビューされて、下に URL が表示されたら成功です!

その URL にアクセスしても画像が表示されるはずです。

ステップ 6:サーバーを永続的に稼働させる

永続的に安定して稼働させるためにプロセス管理ツール pm2 を使用します。

# グローバルにインストール
sudo npm install pm2 -g
# アプリケーションをpm2で起動
pm2 start server.js

これでもう一度 index.html からファイルをアップロードしてみて何もエラーがなければ成功です!

まとめ

  • Express でサーバーを立てて、画像をアップロードすることができる
  • ファイルのアップロードには multer を用いる
  • 永続的にサーバーを起動させておくには pm2 を用いる

最後に

これで画像をサーバーにアップロードすることができました、このレスポンスとして返ってきた URL を Firestore に保存することで、FireStorage を使わずとも、画像を保存することができるようになります。

もし、Storage が使えなくて困っている方がいればぜひ一度試してみてください!

もしここ間違えているなど気づいた方がいれば連絡いただけると幸いです!

舞鶴高専 プログラマーズコミュニティ部

Discussion