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

如何在Next.js API后端实现多文件加文本字段提交并保存本地上传图片

Next.js API路由处理多文件+文本字段上传方案

前端代码修改

现有前端代码有两个核心问题:一是没有用FormData封装上传内容,二是文件输入的onChange逻辑错误,仅获取了文件的假路径而非真实文件对象。修改后代码如下:

import { useState } from 'react';
import axios from 'axios';

const Information = () => {
    const [institute_logo, setInstitute_logo] = useState(null);
    const [institute_about_head, setInstitute_about_head] = useState('');
    const [institute_about_upload, setInstitute_about_upload] = useState(null);
    // 替换为你实际的机构ID
    const Id = '你的机构ID';

    const handleLogoChange = (e) => {
        setInstitute_logo(e.target.files[0]);
    }

    const Info = async (e) => {
        e.preventDefault();
        // 使用FormData封装混合类型数据
        const formData = new FormData();
        formData.append('institute_logo', institute_logo);
        formData.append('institute_about_head', institute_about_head);
        formData.append('institute_about_upload', institute_about_upload);

        await axios.patch(`/api/institute/Information/${Id}`, formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        })
    }
                    
    return (   
        <div>
            <form onSubmit={Info}>
                <input 
                    type="file"
                    id="institute_logo"
                    name="institute_logo"
                    placeholder="Upload Image" 
                    className='shadow appearance-none border-gray rounded w-1/2 py-2 px-3 leading-tight focus:outline-none focus:shadow-outline'
                    onChange={handleLogoChange}
                />
                <div className='mt-2 flex flex-col'>
                    <label htmlFor="institute_about_head" className='font-medium'>Main Heading</label>
                    <input 
                        type="text" 
                        id="institute_about_head"
                        name="institute_about_head"
                        placeholder="About Us" 
                        className='border-2 border-gray-light rounded w-3/4 pl-1.5 h-9 mt-1'
                        onChange={(e) => setInstitute_about_head(e.target.value)} 
                    />
                </div>
                <div>
                    <input 
                        type="file"
                        id="institute_about_upload" 
                        name="institute_about_upload"
                        placeholder="Upload Image" 
                        className='border-2 border-gray-light rounded w-3/4 pl-1.5 h-9 mt-2 shadow appearance-none' 
                        onChange={(e) => setInstitute_about_upload(e.target.files[0])}
                    />
                </div>
                <button type="submit">提交</button>
            </form>
        </div>
    )
}
                
export default Information;

后端API代码修改

Next.js原生API路由默认会解析请求体为JSON,不支持multipart/form-data类型的文件上传请求,需要借助formidable库处理表单数据,同时关闭默认的body解析。

  1. 先安装依赖:
    npm install formidable fs-extra
  2. 修改API路由代码:
import formidable from 'formidable';
import fs from 'fs-extra';
import path from 'path';
import institute from '你的mongoose模型路径';

// 关闭Next.js默认的body解析
export const config = {
  api: {
    bodyParser: false,
  },
};

export default async function handler(req, res) {
    let {Id} = req.query;
    if (req.method === 'PATCH') {
        // 初始化formidable解析器
        const form = formidable({
            uploadDir: path.join(process.cwd(), 'public/upload'),
            keepExtensions: true,
            filename: (name, ext, part) => {
                // 重命名文件避免重复
                return `${Date.now()}-${part.name}${ext}`;
            }
        });

        // 提前创建上传目录
        await fs.ensureDir(path.join(process.cwd(), 'public/upload'));

        // 解析请求
        const [fields, files] = await form.parse(req);
        
        // 提取文本字段,formidable返回的字段是数组,取第一个即可
        const institute_about_head = fields.institute_about_head[0];
        // 提取文件访问路径
        const institute_logo_path = `/upload/${files.institute_logo[0].newFilename}`;
        const institute_about_upload_path = `/upload/${files.institute_about_upload[0].newFilename}`;

        const payload = {
            institute_about_head,
            institute_logo: institute_logo_path,
            institute_about_upload: institute_about_upload_path
        }
                            
        let instituteAdditionalData = await institute.findOneAndUpdate({ _id: Id }, payload, { new: true }).lean();
        if (instituteAdditionalData) {
            res.status(200).json({Message:"Institute Details updated successfully"})
        }
    }      
}

注意事项

  • 本地存储的文件可以通过你的域名 + 存到数据库的路径直接访问
  • 生产环境建议将文件存储到云存储服务,避免Serverless平台的临时文件系统限制
  • 可自行添加文件类型、大小校验逻辑,避免非法文件上传

内容的提问来源于stack exchange,提问作者happy kaul

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 18:18:01