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

NextJS 14 Server Page上传文件至外部API时Express端收不到文件

问题:Next.js Server Page 文件上传至Express服务器时req.files为空

重要提示

必须使用Server Page,否则会用客户端组件+axios实现。

尝试将文件上传到外部Express服务器,但API路由接收请求时req.files.file为空、未定义或无内容。

前端检测情况

表单提交触发action时能正常获取到文件,console.log(avatar)输出:

file: File {
  size: 476026,
  type: 'image/jpeg',
  name: 'Delta-Force-Operator-in-a-Chinook_4x-scaled.jpg',
  lastModified: 1716527617781
}

后端接收问题

Express端使用express-fileupload库,期望通过req.files.file(file是输入框名称)获取文件,但服务器始终接收不到文件,终端打印{}(空对象)。

Express后端代码:

exports.uploadObject = asyncHandler(async (req, res, next) => {
  // 无文件时终止执行
  console.dir(req.files);
  
  if (!req.files || Object.keys(req.files).length === 0 || !req.files.file) {
    return next(new ErrorResponse(`No file uploaded`, 400));
  }

  /*
  其他业务逻辑
  */
      // 返回结果
      res.status(201).json({
        success: true,
        data: "success"
      });
    });
  });
});

前端Server Page代码

const upgradeAvatar = async (formData) => {
  'use server'
  const avatar = formData.get('file')

  const rawFormData = {
    userId: auth?.data?._id,
    username: auth?.data?.username,
    userEmail: auth?.data?.email,
    onModel: 'User',
    album: 'profile-avatars',
    file: avatar,
  }
  // 输出文件对象,能正常打印
  console.log(rawFormData.file);
  // 调用外部API的函数
  await uploadFile(rawFormData)
}

<form action={upgradeAvatar}>
  <label htmlFor="file" className="form-label">
    File
  </label>
  <input
    id="file"
    name="file"
    type="file"
    className="form-control mb-3"
    accept={`image/*`}
  />
  <FormButtons />
</form>

解决方法

核心问题是你直接把File对象塞进普通JSON对象传给后端,而express-fileupload只认multipart/form-data格式的请求,不认JSON。

1. 前端重新构建FormData

在upgradeAvatar函数里,放弃普通对象,用FormData实例来包装所有字段和文件:

const upgradeAvatar = async (formData) => {
  'use server'
  const avatar = formData.get('file')

  const uploadFormData = new FormData();
  // 逐一添加非文件字段
  uploadFormData.append('userId', auth?.data?._id);
  uploadFormData.append('username', auth?.data?.username);
  uploadFormData.append('userEmail', auth?.data?.email);
  uploadFormData.append('onModel', 'User');
  uploadFormData.append('album', 'profile-avatars');
  // 添加文件,名称要和后端期望的`file`完全一致
  uploadFormData.append('file', avatar);

  // 调用外部API
  await uploadFile(uploadFormData)
}

2. 修正uploadFile的请求配置

如果uploadFile是你自己封装的函数,注意两点:

  • 不要手动设置Content-Type为application/json,浏览器会自动为FormData生成带边界的multipart/form-data头
  • 用POST请求,直接把FormData作为请求体发送

示例uploadFile实现:

async function uploadFile(formData) {
  const response = await fetch('你的Express API地址', {
    method: 'POST',
    body: formData,
    // 不需要手动设置Content-Type
  });
  return response.json();
}

3. 检查Express中间件顺序

确保express-fileupload中间件在express.json()这类JSON解析中间件之前配置,避免请求被提前解析成JSON:

const express = require('express');
const fileUpload = require('express-fileupload');
const app = express();

// 先配置文件上传中间件
app.use(fileUpload({
  createParentPath: true, // 可选,自动创建文件保存目录
}));

// 再配置其他中间件
app.use(express.json());

// 挂载上传路由
app.post('/upload', uploadObject);

调整完成后,后端就能通过req.files.file正常获取到上传的文件了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 14:26:12