You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Next.js图片上传时的ERR_INVALID_ARG_TYPE路径未定义错误

图片上传功能报错解决建议

问题背景

使用Next.js开发图片上传功能,上传API负责将图片存储到独立目录,但上传时触发以下错误:

error - unhandledRejection: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined

现有代码

后端API代码(/api/upload)

import formidable from "formidable";
import path from "path";
import { renameSync } from "fs";

export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function upload(req, res) {
  if (req.method !== "POST") {
    return res.status(405).json({ error: "Method not allowed" });
  }

  const form = new formidable.IncomingForm({
    keepExtensions: true,
    maxFileSize: 200 * 1024 * 1024,
  });

  return new Promise((resolve, reject) => {
    form.parse(req, async (err, fields, files) => {
      if (err) {
        res.status(500).json({ error: err.message });
        return resolve();
      }

      if (!files.image) {
        res.status(422).json({ error: "Bad request: missing image field" });
        return resolve();
      }

      const ext = path.extname(files.image.path);
      const uuid = Math.random().toString(26).slice(2);
      await renameSync(files.image.path, `./public/images/${uuid}${ext}`);

      res.status(201).json({
        uuid,
        url: `/images/${uuid}${ext}`,
      });
      return resolve();
    });
  });
}

前端组件代码

import React from "react";

export default function UploadImage() {
const [imgsSrc, setImgsSrc] = React.useState([]);

const uploadToClient = (e) => {
    for (const file of e.target.files) {
        setImgsSrc((imgs) => [...imgs, file]);
    }
};

const uploadToServer = async () => {
    let formData = new FormData();
    for (const file of imgsSrc) {
        formData.append('image', file, file.name)
    }    
    const response = await fetch("/api/upload", {
        method: "POST",
        body: formData
    });
};

return(
  <div>
    <h3>Upload photos</h3>
    <input onChange={uploadToClient} type="file" name="file" multiple />

    <div>
      {imgsSrc.map((link) => (
         <img src={link} style={{ width: 200, height: 200 }} />
      ))}
    </div>
    <button type="submit" onClick={uploadToServer}>Send to server</button>
  </div>
    )
}

错误原因及修复方案

1. 多文件上传的字段处理问题

前端一次上传多个文件时,formData.append('image', file, file.name)会将所有文件存入同一个image字段,而旧版formidable默认会将多值字段转为数组,导致files.image变成数组而非单个对象,此时访问files.image.path就会得到undefined。

修复:
在后端兼容单文件和多文件的情况,遍历处理每个文件:

// 替换原文件处理逻辑
const images = Array.isArray(files.image) ? files.image : [files.image];
const uploadedUrls = [];

for (const image of images) {
  const ext = path.extname(image.path);
  const uuid = Math.random().toString(26).slice(2);
  renameSync(image.path, `./public/images/${uuid}${ext}`);
  uploadedUrls.push({ uuid, url: `/images/${uuid}${ext}` });
}

res.status(201).json({ urls: uploadedUrls });

2. 同步方法误用await

renameSync是fs的同步方法,不需要加await关键字,误用会导致不必要的Promise处理,可能触发未捕获异常。

修复:
删除await renameSync(...)中的await。

3. 前端图片预览错误

直接将File对象作为img的src属性无法显示图片,需要通过URL.createObjectURL生成预览链接。

修复:
修改前端状态存储和渲染逻辑:

const [imgs, setImgs] = React.useState([]);

const uploadToClient = (e) => {
  for (const file of e.target.files) {
    const previewUrl = URL.createObjectURL(file);
    setImgs((prev) => [...prev, { file, previewUrl }]);
  }
};

// 渲染预览图
{imgs.map((item, index) => (
  <img key={index} src={item.previewUrl} style={{ width: 200, height: 200 }} />
))}

// 上传时使用真实File对象
const uploadToServer = async () => {
  let formData = new FormData();
  for (const { file } of imgs) {
    formData.append('image', file, file.name);
  }    
  const response = await fetch("/api/upload", {
    method: "POST",
    body: formData
  });
};

4. 路径稳定性优化(可选)

使用相对路径./public/images可能在不同环境下出现问题,建议用path.resolve生成绝对路径:

const targetPath = path.resolve(process.cwd(), 'public', 'images', `${uuid}${ext}`);
renameSync(image.path, targetPath);

最终修复后的后端代码

import formidable from "formidable";
import path from "path";
import { renameSync } from "fs";

export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function upload(req, res) {
  if (req.method !== "POST") {
    return res.status(405).json({ error: "Method not allowed" });
  }

  const form = new formidable.IncomingForm({
    keepExtensions: true,
    maxFileSize: 200 * 1024 * 1024,
  });

  return new Promise((resolve) => {
    form.parse(req, (err, fields, files) => {
      if (err) {
        res.status(500).json({ error: err.message });
        return resolve();
      }

      if (!files.image) {
        res.status(422).json({ error: "Bad request: missing image field" });
        return resolve();
      }

      const images = Array.isArray(files.image) ? files.image : [files.image];
      const uploadedUrls = [];

      for (const image of images) {
        const ext = path.extname(image.path);
        const uuid = Math.random().toString(26).slice(2);
        const targetPath = path.resolve(process.cwd(), 'public', 'images', `${uuid}${ext}`);
        renameSync(image.path, targetPath);
        uploadedUrls.push({ uuid, url: `/images/${uuid}${ext}` });
      }

      res.status(201).json({ urls: uploadedUrls });
      return resolve();
    });
  });
}

内容的提问来源于stack exchange,提问作者Sajith Wijerathne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 01:15:39