Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】 API
Azure Blob Storage にファイルをアップロードする方法【Next.js × React】
この記事は約26分で読めます。

でじぼうです。

今回は Azure Blob Storage にファイルをアップロードする機能を Next.js(App Router)× React で実装した方法をご紹介します。

でじぼう
でじぼう

この記事は下記の方がおすすめ!

  • Azure側の設定がわからない
  • APIはどのように記載するの?
  • 実装方法が知りたい

Instagramフォロワー数9,500人を越える人気のもち・大福店 えにかいたもち

全体構成

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

Azure 側の準備

ファイルを保存する先として Azure Blob Storage を使うために、まずはAzure側での初期設定を行いましょう。

STEP1:ストレージアカウントを作成

  1. Azureポータル にログイン
  2. 左上の「≡」メニューから「ストレージアカウント」を選択し、「+作成」をクリック
  3. 以下の1ように項目を入力(最低限でOK)
  4. 下部の「確認および作成」→「作成」を押す
  5. デプロイ完了後、「リソースに移動」ボタンをクリック

1

項目設定値
サブスクリプション任意(通常は1つ)
リソースグループ任意(新規作成でもOK)
ストレージアカウント名例:myuploadstorage123(一意な名前)
リージョンお住まいに近い場所(東日本ならJapan East)
パフォーマンスstandard
冗長性ローカル冗長ストレージ (LRS)

STEP2:Blobコンテナーを作成

  1. ストレージアカウントの画面左メニューから「データストレージ」→「コンテナー」を選択
  2. 上部の「+コンテナー」ボタンを押して以下の2ように項目を入力
  3. 作成」ボタンを押す

2

項目設定値
名前例:upload
パブリックアクセスレベルプライベート(推奨)

STEP3:接続文字列を取得して .env.local に設定

  1. ストレージアカウントの左メニューをスクロールし、「セキュリティとネットワーク」セクションにある「アクセスキー」をクリック
  2. 「key1」の項目にある「接続文字列」をコピー
  3. プロジェクト直下の .env.local ファイルに以下を追加
AZURE_STORAGE_CONNECTION_STRING=DefaultEndpointsProtocol=(コピーした内容)
AZURE_CONTAINER_NAME=(設定した名前)

.env.local を変更したあとは、Next.js の開発サーバーを再起動してください。

ファイルアップロード用UIの作成(React)

"use client";

import { useState, useRef } from "react";

export default function DragAndDropUploader() {
  // ドラッグ中かどうかの状態
  const [isDragging, setIsDragging] = useState(false);

  // メッセージ表示用(成功・エラー)
  const [message, setMessage] = useState("");

  // input要素の参照(隠してボタンから開く用)
  const fileInputRef = useRef<HTMLInputElement>(null);

  // 選択されたファイル一覧
  const [selectedFiles, setSelectedFiles] = useState<File[]>([]);

  // ファイルがドロップされた時の処理
  const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    setIsDragging(false);
    const files = Array.from(e.dataTransfer.files); // FileList → 配列に変換
    if (files.length === 0) return;
    setSelectedFiles(files);
  };

  // ドラッグ中(枠が赤くなる)
  const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    setIsDragging(true);
  };

  // ドラッグが外れたとき(赤枠を戻す)
  const handleDragLeave = () => setIsDragging(false);

  // ファイル選択時の処理
  const handleFileSelect = (e: React.ChangeEvent<HTMLInputElement>) => {
    const files = Array.from(e.target.files || []);
    if (files.length === 0) return;
    setSelectedFiles(files);
  };

  // 一括取消(ファイルクリア)
  const handleClearFiles = () => {
    setSelectedFiles([]);
    setMessage("");
  };

  // ボタンクリック → input をクリックさせる
  const handleButtonClick = () => {
    fileInputRef.current?.click();
  };

  // アップロード処理
  const handleUpload = async () => {
    if (selectedFiles.length === 0) {
      setMessage("❌ ファイルが選択されていません");
      return;
    }

    const formData = new FormData();
    selectedFiles.forEach((file) => formData.append("files", file));

    try {
      // APIにPOST
      const res = await fetch("/api/upload", {
        method: "POST",
        body: formData,
      });

      if (res.ok) {
        setMessage("✅ アップロード成功しました");
      } else {
        const data = await res.json();
        setMessage("❌ アップロード失敗: " + (data.error || res.statusText));
      }
    } catch {
      setMessage("❌ アップロード中にエラーが発生しました");
    }
  };

  return (
    <div className="m-5 mx-auto w-fit">
      <h2>📥 スキルシートをアップロード</h2>

      {/* ドラッグ&ドロップ枠 */}
      <div
        onDrop={handleDrop}
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        className={`w-[620px] h-[320px] border-2 border-dashed rounded p-5 text-center transition-colors duration-300 ${
          isDragging ? "border-red-500" : "border-gray-300"
        } bg-gray-100 flex items-center justify-center`}
      >
        <div>
          <p>{isDragging ? "ここにドロップ" : "ファイルをドラッグ&ドロップ"}</p>
          <p>または</p>
          <button
            onClick={handleButtonClick}
            className="bg-red-500 text-white px-4 py-2 rounded"
          >
            ファイルを選択
          </button>
        </div>

        {/* ファイル選択用input(非表示) */}
        <input
          type="file"
          multiple
          ref={fileInputRef}
          onChange={handleFileSelect}
          style={{ display: "none" }}
        />
      </div>

      {/* 選択されたファイルの表示 + ✕ボタン */}
      {selectedFiles.length > 0 && (
        <div className="mt-4 text-left">
          <div className="flex items-start justify-between mb-2">
            <p className="font-semibold">選択中のファイル</p>
            <button
              onClick={handleClearFiles}
              className="font-semibold text-sm text-red-600 hover:underline"
            >
              一括取消
            </button>
          </div>
          <ul>
            {selectedFiles.map((file, index) => (
              <li key={index} className="flex items-center justify-between mb-1">
                <span>{file.name}</span>
                <button
                  onClick={() =>
                    setSelectedFiles((prev) =>
                      prev.filter((_, i) => i !== index)
                    )
                  }
                  className="text-red-600 font-bold"
                >

                </button>
              </li>
            ))}
          </ul>
        </div>
      )}

      {/* アップロードボタン */}
      <div>
        <button
          onClick={handleUpload}
          className="bg-green-700 text-white px-4 py-2 rounded mt-5"
        >
          アップロード
        </button>
        {message && <p className="mt-2">{message}</p>}
      </div>
    </div>
  );
}

ファイルアップロードAPIの作成(Next.js × Azure SDK)

仕様
ファイル名が一意になるように、アップロードされたファイル名の末尾に
_YYYYMMDD_hhmm」と日時を付与してからAzure Blob Storage にアップロードする

import { NextResponse } from "next/server";
import { BlobServiceClient } from "@azure/storage-blob";

// POSTメソッドで呼び出されたときの処理
export async function POST(req: Request) {
  try {
    // フロントから送られてきたファイル付きのデータ(FormData)を受け取る
    const formData = await req.formData();

    // name="files" という名前で送られてきたファイル全部取得
    const files = formData.getAll("files") as File[];

    // ファイルが1つもなかったらエラーを返す
    if (!files.length) {
      return NextResponse.json(
        { error: "ファイルがありません" },
        { status: 400 }
      );
    }

    // Azure Storage に接続するためのクライアントを作成
    const blobService = BlobServiceClient.fromConnectionString(
      process.env.AZURE_STORAGE_CONNECTION_STRING! // .env.local に設定した接続文字列
    );

    // コンテナー(事前に作成済み)に接続
    const container = blobService.getContainerClient(
      process.env.AZURE_CONTAINER_NAME!
    );

    // ファイルごとに繰り返す
    for (const file of files) {
      // タイムスタンプを付けて、ファイル名の重複を防ぐ
      const now = new Date();
      const timestamp = `${now.getFullYear()}${String(
        now.getMonth() + 1
      ).padStart(2, "0")}${String(now.getDate()).padStart(2, "0")}_${String(
        now.getHours()
      ).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;

      // 元のファイル名と拡張子を分離
      const originalName = file.name;
      const ext = originalName.includes(".")
        ? "." + originalName.split(".").pop()
        : "";
      const base = originalName.replace(ext, "");

      // 一意なファイル名を作成(例:resume_20250626_1030.pdf)
      const uniqueName = `${base}_${timestamp}${ext}`;

      // Fileオブジェクト → ArrayBuffer に変換
      const arrayBuffer = await file.arrayBuffer();

      // ArrayBuffer → Node.js の Buffer に変換(Azure用)
      const buffer = Buffer.from(arrayBuffer);

      // Azure上の「保存先ファイル(Blob)」を指定
      const blockBlob = container.getBlockBlobClient(uniqueName);

      // ファイルをアップロード(bufferとして保存)
      await blockBlob.uploadData(buffer);
    }

    // 成功レスポンスを返す
    return NextResponse.json({
      message: "すべてのファイルをアップロードしました",
    });
  } catch (error) {
    // エラーが起きた場合はログを出してエラーを返す
    console.error("アップロードエラー:", error);
    return NextResponse.json({ error: "アップロード失敗" }, { status: 500 });
  }
}

実行画面

Azure Blob Storage にまだファイルがアップロードされていない状態

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

アップロード画面

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

ファイルをアップロードすると、選択中のファイルが表示される

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

アップロードボタンを押下すると、アップロード完了

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

Azure Blob Storage にファイルが格納されていることを確認

Azure Blob Storage にファイルをアップロードする方法【Next.js × React】

コメント