Next.js API Routes提交请求长期Pending问题排查求助
Next.js API Routes 处理文件表单请求一直pending的问题
我用Next.js API Routes搭建了无服务器应用,前端提交带文件的表单时,请求始终处于pending状态,控制台也没有日志输出。希望只通过Next.js内置API Routes实现功能,不想搭Express服务器,请问哪里漏了?
提交页面代码
import React, { useState } from 'react'; import { Container, Form, Button } from 'react-bootstrap'; import axios from 'axios'; // ... other imports export default function ContestSubmission() { const [formData, setFormData] = useState({ firstName: '', lastName: '', email: '', file: null, }); const handleInputChange = (e) => { const { name, value, type, files } = e.target; setFormData((prevData) => ({ ...prevData, [name]: type === 'file' ? files[0] : value, })); }; const handleSubmit = async (e) => { e.preventDefault(); // Use formData to send the data const dataToSend = new FormData(); dataToSend.append('firstName', formData.firstName); dataToSend.append('lastName', formData.lastName); dataToSend.append('email', formData.email); dataToSend.append('file', formData.file); try { const response = await axios.post('/api/contest-submission', dataToSend); if (response.data.success) { console.log('Submission successful'); } else { console.error('Submission failed:', response.data.error); } } catch (error) { console.error('Request error:', error); } }; return ( <div className={styles.wrapper}> <div className={styles.container}> <h2>Submit Your Entry</h2> <Form onSubmit={handleSubmit} encType="multipart/form-data"> // ... other form groups <Button className="enter-button" type="submit"> Submit </Button> </Form> </div> </div> ); }
/api/contest-submission.js代码
const { config } = require('dotenv'); const formidable = require('formidable'); // ... other imports config(); export default async function handler(req, res) { if (req.method === 'POST') { const form = formidable({}); form.uploadDir = './uploads'; form.parse(req, (parseError, fields, files) => { if (parseError) { res.status(500).json({ success: false, error: 'Error parsing form data.' }); return; } const { firstName, lastName, email } = fields; const { file } = files; const ipAddress = req.connection.remoteAddress; const submissionTime = new Date(); // Get the current date and time const uniqueFileName = `${uuidv4()}.jpg`; const filePath = `${form.uploadDir}/${uniqueFileName}`; fs.rename(file.path, filePath, (renameError) => { if (renameError) { res.status(500).json({ success: false, error: 'Error saving the file.' }); return; } const connection = createDBConnection(); connection.connect(); const query = 'INSERT INTO submissions (first_name, last_name, email, file_path, ip_address, submission_datetime) VALUES (?, ?, ?, ?, ?, ?)'; connection.query( query, [firstName, lastName, email, uniqueFileName, ipAddress, submissionTime], (dbError) => { if (dbError) { res.status(500).json({ success: false, error: 'Error inserting data into the database.' }); } else { res.status(200).json({ success: true }); } connection.end(); } ); }); }); } else { res.status(405).json({ success: false, error: 'Method not allowed.' }); } }
提交表单时Payload正常,但请求一直pending无响应,也看不到任何控制台日志。
问题原因及修复方案
1. 未禁用Next.js默认的body解析器
Next.js API Routes默认会自动解析请求体,但处理multipart/form-data时必须手动禁用,否则formidable无法正确读取原始请求流。在API路由文件顶部添加配置:
export const config = { api: { bodyParser: false, }, };
2. 多层回调嵌套导致的未响应风险
你的代码使用了多层回调(form.parse → fs.rename → connection.query),如果某一步出现未捕获的错误,会导致响应从未发送。建议改用Promise化写法,确保所有分支都能返回响应:
import { promises as fs } from 'fs'; import { v4 as uuidv4 } from 'uuid'; export const config = { api: { bodyParser: false, }, }; export default async function handler(req, res) { if (req.method !== 'POST') { return res.status(405).json({ success: false, error: 'Method not allowed.' }); } try { // 确保uploads目录存在 const uploadDir = './uploads'; await fs.access(uploadDir).catch(() => fs.mkdir(uploadDir, { recursive: true })); const form = formidable({ uploadDir }); // 将form.parse转为Promise const [fields, files] = await new Promise((resolve, reject) => { form.parse(req, (err, fields, files) => err ? reject(err) : resolve([fields, files])); }); const { firstName, lastName, email } = fields; const { file } = files; const ipAddress = req.connection.remoteAddress; const submissionTime = new Date(); const uniqueFileName = `${uuidv4()}.jpg`; const filePath = `${uploadDir}/${uniqueFileName}`; // 使用Promise版fs.rename await fs.rename(file.path, filePath); // 数据库操作改用Promise化写法(需确保createDBConnection返回支持Promise的连接) const connection = createDBConnection(); await connection.connect(); const query = 'INSERT INTO submissions (first_name, last_name, email, file_path, ip_address, submission_datetime) VALUES (?, ?, ?, ?, ?, ?)'; await connection.query(query, [firstName, lastName, email, uniqueFileName, ipAddress, submissionTime]); await connection.end(); res.status(200).json({ success: true }); } catch (error) { console.error('处理错误:', error); // 添加日志便于排查 res.status(500).json({ success: false, error: error.message || '请求处理失败' }); } }
3. 缺少uploads目录
如果./uploads目录不存在,fs.rename会抛出错误且未被捕获,导致请求挂起。上面的修复代码已添加目录检查与自动创建逻辑。
4. 依赖未正确安装
确认已安装所需依赖:
npm install formidable uuid
内容的提问来源于stack exchange,提问作者kastaplastislife
相关产品推荐
相关产品推荐

