如何在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解析。
- 先安装依赖:
npm install formidable fs-extra - 修改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
相关产品推荐
相关产品推荐

