📂

初心者すぎてNext.jsでform-dataのファイルアップロードを実装した時のハマったとこ

2022/04/30に公開

メインはバックエンド、副業でフロントエンドエンジニアをしていてCSSは万年初心者のmikiです。

仕事でapi側でファイルアップロードを実装する時にハマったことがあったのでメモかねて。

タイトルではform-dataで実装とありますが最初は2パターンのファイルを送信する実装を考えました。

  • form-dataで送信する
  • base64に変換して送信する

base64は文字列にしてるので扱いやすいですが。デコードとエンコードが面倒でコストかかるなという印象。サイズも大きくなりがちなのでとりあえずform-dataを採用することにしました。
どちらかというとform-dataが王道ではある気がしますが、base64変換する方もそれなりに実装を見かけることはあるので、扱わないといけないデータ&保存方法によって比較して見るのがいいかなとかそんな感じです。

form-data送信の実装サンプル

フロントエンド

import axios from "axios";

export default function Images() {
  const handleUploadClick = async (e) => {
    const file = e.target.files[0];
    const formData = new FormData();
    formData.append('file', file);

    try {
      await axios.post(`アップロード先エンドポイント`,
        formData
      );
    } catch (e) {
      console.error(e);
    }
  };

  return (
    <div style={{ padding: 20 }}>
      <label htmlFor="upload-button" style={{ border: "1px solid #222", borderRadius: 10, padding: 10, cursor: "pointer" }}>
        <input
          accept="image/*"
          id="upload-button"
          type="file"
          onChange={handleUploadClick}
          hidden
        />
        Choose file
      </label>
    </div >
  );
};

バックエンド

const formidable = require("formidable");

// これ必要なことに気づかなかった↓
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async (req, res) => {
  if (req.method !== "POST") return;

  const form = new formidable.IncomingForm();

  form.parse(req, async function (err, fields, files) {
    if (err) {
      res.statusCode = 500;
      res.json({
        method: req.method,
        error: err
      });
      res.end();
      return;
    }
    const file = files.file;
    // ファイルをなんやかんやする
  });
};

しばらく気づかなかったハマりポイント

ここのconfig部分なしで最初実装していたんですが

// これ必要なことに気づかなかった↓
export const config = {
  api: {
    bodyParser: false,
  },
};

ファイルがパースされなくてなんでだろう?と思ってしばらく考えていました。どうもnextjsはデフォルトでrrequest.bodyをパースしてくれるようで。。。
そのためストリームでファイルが受信できなかったみたいです。

というわけでNext.jsのAPIミドルウェアのページを見ると・・・
https://nextjs.org/docs/api-routes/api-middlewares#custom-config

bodyParser is automatically enabled. If you want to consume the body as a Stream or with raw-body, you can set this to false.

なるほど。

これでストリームでファイルが受けれるようになりました!Happy!🥳

Discussion