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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 13:22:15