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

Multer报Unexpected end of form错误:基础文本表单示例无法运行

问题:Multer解析multipart/form-data请求时出现"Unexpected end of form"错误

当前运行一个基础Multer文本表单示例时失败,相关代码如下:

'use strict';

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

const PORT = 8077;
app.listen(PORT, () => {
  console.info(`Started http://localhost:${PORT} (PID: ${process.pid})`);
  const multer = require('multer');
  const upload = multer();
  app.post('/post', upload.none(), (req, res) => {
    console.log("POST");
    console.log(req.body);
  });
  postSomething();
});

async function postSomething() {
  const fetch = require('node-fetch');
  let res = await fetch('http://localhost:8077/post', {
    method: 'POST',
    credentials: 'include',
    headers: {'Content-type': 'multipart/form-data; boundary=abcde12345' },
    body: `--abcde12345
Content-Disposition: form-data; name="id"
Content-Type: text/plain
foo
--abcde12345--`
  });
  console.log(res.status);
}

解析请求体时出现如下错误:

Error: Unexpected end of form
    at Multipart._final (C:\projects\bar\node_modules\busboy\lib\types\multipart.js:588:17)
    at callFinal (node:internal/streams/writable:696:27)
    at prefinish (node:internal/streams/writable:725:7)
    at finishMaybe (node:internal/streams/writable:735:5)
    at Multipart.Writable.end (node:internal/streams/writable:633:5)
    at IncomingMessage.onend (node:internal/streams/readable:693:10)
    at Object.onceWrapper (node:events:627:28)
    at IncomingMessage.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1358:12)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)

问题原因及修复方案

核心问题

你手动构造的multipart请求体不符合HTTP规范:multipart/form-data要求所有换行必须用CRLF(即\r\n),而非单纯的LF(\n)。Multer底层依赖的Busboy解析器靠CRLF识别字段边界和内容结束位置,用LF会导致解析器无法正确识别结束标记,从而抛出"Unexpected end of form"错误。另外,字段头和字段值之间需要空一行(\r\n\r\n),你当前代码也缺少这个关键的空行。

修复方法1:修正手动构造的请求体格式

修改postSomething函数里的body内容,把所有换行替换为\r\n,并补充字段头与值之间的空行:

async function postSomething() {
  const fetch = require('node-fetch');
  let res = await fetch('http://localhost:8077/post', {
    method: 'POST',
    credentials: 'include',
    headers: {'Content-type': 'multipart/form-data; boundary=abcde12345' },
    body: `--abcde12345\r\nContent-Disposition: form-data; name="id"\r\nContent-Type: text/plain\r\n\r\nfoo\r\n--abcde12345--\r\n`
  });
  console.log(res.status);
}

修复方法2:使用FormData自动构造请求体(推荐)

手动拼接multipart格式容易出错,更可靠的方式是用FormData对象自动生成符合规范的请求体,fetch会自动处理Content-Type头和边界:

async function postSomething() {
  const fetch = require('node-fetch');
  const form = new FormData();
  form.append('id', 'foo');
  
  let res = await fetch('http://localhost:8077/post', {
    method: 'POST',
    credentials: 'include',
    body: form
  });
  console.log(res.status);
}

额外优化建议

把Multer初始化和路由注册代码移到app.listen之前,避免逻辑嵌套混乱,同时给接口补充响应避免请求挂起:

'use strict';

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

const PORT = 8077;

app.post('/post', upload.none(), (req, res) => {
  console.log("POST");
  console.log(req.body);
  res.sendStatus(200); // 补充响应,避免请求挂起
});

app.listen(PORT, () => {
  console.info(`Started http://localhost:${PORT} (PID: ${process.pid})`);
  postSomething();
});

// postSomething函数...

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 04:31:03