0
0

multerのエラー:Error: Unexpected end of formの解決法

Posted at

環境

  • Node.js、Express
  • multer

multer について

  • HTTP 通信で送られた Content-Type が multipart/form-data のファイルを処理するためのミドルウェア
  • ファイルをメモリやストレージに保存することができる

やりたいこと

  • HTTP リクエストで受信した multipart/form-data のファイルをメモリに保存した後、ストレージに保存したかった
  • 以下の方法で実現しようとした
    • メモリに保存するときは、multer.memoryStorage()
    • ストレージに保存するときは、multer.diskStorage()

2024-05-06-19-30-10.png

事象

  • multerの.single() を 2 つミドルウェアに定義するとエラーになる
router.post(
  "/upload/new",
  // メモリに保存
  multerMemory.single("markdown"),
  async (req, res, next) => {
    req.headers.uuid = crypto.randomUUID();
    req.headers.userEmail = await getUserEmail(user_id);
    req.headers.filedir = `${process.env.STR_DIR_PATH}/users/${req.headers.userEmail}/files/${req.headers.uuid}`;

    // ディレクトリを作成
    await fs.promises.mkdir(req.headers.filedir, { recursive: true });

    next();
  },
  // ストレージに保存
  multerStorage.single("markdown"),
  // 以降のミドルウェアは省略

エラー文

Error: Unexpected end of form
    at Multipart.\_final (アプリのパス\node_modules\busboy\lib\types\multipart.js:588:17)
    at callFinal (node:internal/streams/writable:698:12)
    at prefinish (node:internal/streams/writable:710:7)
    at finishMaybe (node:internal/streams/writable:720:5)
    at Writable.end (node:internal/streams/writable:634:5)
    at onend (node:internal/streams/readable:705:10)
    at process.processTicksAndRejections (node:internal/process/task_queues:77:11)

multipart/form-data のストリームが完全に終わる前に終了してしまうとこのエラーが出るようです。

2024-05-06-19-47-14.png

解決

なぜストリームが途中で終わってしまうかの原因はわかりませんでしたが、メモリに保存したファイルを fs でストレージに移すように変更したことで解決しました。

2024-05-06-19-31-28.png

multer でメモリ保存されたファイルは、req.file.buffer に格納されるので、それを使用しました。

router.post(
  "/upload/new",
  multerUpload.single("markdown"),
  async (req, res, next) => {
    try {
      if (!req.file) {
        return res.status(400).send("No file uploaded.");
      }

      const buffer = req.file.buffer;
      const uuid = crypto.randomUUID();
      const userEmail = await getUserEmail(user_id);
      const filedir = `${process.env.STR_DIR_PATH}/users/${userEmail}/files/${uuid}`;
      const filename = decodeURIComponent(req.file.originalname);
      const filePath = path.join(filedir, filename);

      // UUIDのディレクトリを作成
      await fs.promises.mkdir(filedir, { recursive: true });

      // ファイル保存
      await fs.promises.writeFile(filePath, buffer);

Tips

ちなみに、multerの.single()はそれ自体がミドルウェア関数で、以下のようにミドルウェア関数の中に入れることはできないです。

async (req, res, next) => {
    multerMemory.single("markdown")
    next();
},
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0