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

如何在Express中读取非本地File对象?fetch文件上传疑问

问题分析与解决方案

你的代码问题出在哪?

你直接把File对象拼进JSON字符串里,JSON只能序列化字符串、数字、布尔、数组、普通对象这类基本类型,File是复杂的二进制对象,转成字符串就会变成[object File],后端自然拿不到实际的文件内容。

能不能不用FormData上传文件?

能,但非常不推荐。

HTTP协议里,上传二进制文件的标准方式是用multipart/form-data格式(也就是FormData对应的格式)。如果非要不用FormData,只能把文件转成Base64编码后放进JSON里,但这种方式有明显缺点:

  • Base64编码会让文件体积增大30%,传输效率更低
  • 处理大文件时,前端转Base64会占用大量内存,容易导致页面卡顿
  • 后端需要额外解码,增加服务器开销

推荐的正确实现(FormData方式)

前端代码修改

subBtn.addEventListener('click', requestCreate);

async function requestCreate(e) {
  e.preventDefault();
  try {
    const formData = new FormData();
    // 添加普通字段
    formData.append('title', name.value);
    formData.append('body', email.value);
    // 添加文件
    if (file.files[0]) formData.append('file', file.files[0]);
    if (file.files[1]) formData.append('file2', file.files[1]);

    const res = await fetch('http://localhost:3000/', {
      method: 'POST',
      body: formData
      // 不要手动设置Content-Type,浏览器会自动添加带边界的multipart/form-data头
    });

    if (!res.ok) throw Error(res.statusText);
  } catch (error) {
    console.log(error);
  }
}

后端代码修改

需要安装multer中间件来解析multipart/form-data格式的请求:

npm install multer

然后修改后端代码:

const express = require('express');
const multer = require('multer');
const app = express();

// 配置multer,这里用内存存储,也可以配置成存储到磁盘
const storage = multer.memoryStorage();
const upload = multer({ storage: storage });

// 使用upload中间件解析文件,fields指定接收的文件字段名
app.post('/', upload.fields([{ name: 'file' }, { name: 'file2' }]), (req, res) => {
  // 普通字段在req.body里
  console.log('title:', req.body.title);
  console.log('body:', req.body.body);
  // 文件在req.files里
  console.log('file:', req.files.file?.[0]); // 文件对象,包含buffer、originalname等属性
  console.log('file2:', req.files.file2?.[0]);
  res.send({ name: 'hello world' });
});

app.listen(3000, () => console.log('Server running on port 3000'));

不推荐的Base64方式(满足不用FormData的需求)

前端代码

subBtn.addEventListener('click', requestCreate);

// 工具函数:把File转成Base64
function fileToBase64(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = reject;
    reader.readAsDataURL(file);
  });
}

async function requestCreate(e) {
  e.preventDefault();
  try {
    // 把文件转成Base64
    const fileBase64 = file.files[0] ? await fileToBase64(file.files[0]) : null;
    const file2Base64 = file.files[1] ? await fileToBase64(file.files[1]) : null;

    const obj = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        title: name.value,
        body: email.value,
        file: fileBase64,
        file2: file2Base64
      })
    };

    const res = await fetch('http://localhost:3000/', obj);
    if (!res.ok) throw Error(res.statusText);
  } catch (error) {
    console.log(error);
  }
}

后端代码

const express = require('express');
const fs = require('fs');
const path = require('path');
const app = express();

app.use(express.json({ limit: '10mb' })); // 要设置更大的请求体限制,因为Base64体积大

app.post('/', (req, res) => {
  const { title, body, file, file2 } = req.body;
  console.log('title:', title);
  console.log('body:', body);

  // 解码Base64并保存文件
  if (file) {
    // 去掉Base64前缀(data:image/png;base64,)
    const base64Data = file.replace(/^data:.+;base64,/, '');
    const buffer = Buffer.from(base64Data, 'base64');
    fs.writeFileSync(path.join(__dirname, 'uploaded-file.png'), buffer);
  }

  res.send({ name: 'hello world' });
});

app.listen(3000, () => console.log('Server running on port 3000'));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 05:22:29