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

不依赖第三方库在Node.js中解析并保存Multipart表单数据

问题分析与解决方案

你的核心问题在于用字符串处理二进制文件数据导致编码损坏,同时正则提取的文件内容可能包含多余的尾部字符,最终导致保存的文件无效。以下是具体修复步骤:

关键问题点

  1. 请求体收集方式错误:你直接将req.body作为字符串处理,但HTTP multipart表单中的文件是二进制数据,转成UTF-16字符串会丢失部分字节,导致文件损坏。
  2. 正则提取的内容包含冗余字符:原正则匹配到的contentData可能包含尾部的\r\n和边界分隔符残留,写入文件后会破坏文件结构。
  3. 文件写入编码错误:使用"binary"编码写入字符串形式的二进制数据,无法还原原始字节。

修复后的完整实现

1. 正确收集请求体(用Buffer而非字符串)

HTTP请求是流,必须用Buffer数组收集二进制数据,避免编码损失:

const http = require('http');
const fs = require('fs');
const { Buffer } = require('buffer');

http.createServer((req, res) => {
  if (req.method === 'POST' && req.headers['content-type']?.startsWith('multipart/form-data')) {
    const bodyChunks = [];
    req.on('data', chunk => bodyChunks.push(chunk));
    req.on('end', () => {
      const bodyBuffer = Buffer.concat(bodyChunks);
      const parsedData = parseMultipartFormData(bodyBuffer);
      
      res.writeHead(200, {'Content-Type': 'application/json'});
      res.end(JSON.stringify(parsedData));
    });
  } else {
    res.writeHead(404);
    res.end();
  }
}).listen(3000);

2. 重写Multipart解析函数(基于Buffer处理)

用Buffer分割和提取数据,避免字符串转码损坏:

function parseMultipartFormData(bodyBuffer) {
  // 从Buffer头部提取边界字符串
  const boundaryStr = bodyBuffer.toString('utf8', 0, bodyBuffer.indexOf('\r\n'));
  const boundary = Buffer.from(boundaryStr + '\r\n');
  const parts = splitBuffer(bodyBuffer, boundary);

  parts.shift(); // 移除开头空部分
  parts.pop();   // 移除结尾的边界结束标记

  const parsedData = {};

  for (const part of parts) {
    // 分割头部和内容:找到第一个\r\n\r\n的位置
    const headerEndIdx = part.indexOf(Buffer.from('\r\n\r\n'));
    if (headerEndIdx === -1) continue;

    const headerStr = part.toString('utf8', 0, headerEndIdx);
    const contentBuffer = part.slice(headerEndIdx + 4); // 跳过\r\n\r\n

    if (headerStr.includes('filename')) {
      // 解析文件字段
      const nameMatch = headerStr.match(/name="(.+)"/);
      const filenameMatch = headerStr.match(/filename="(.+)"/);
      const contentTypeMatch = headerStr.match(/Content-Type: (\w+\/\w+)/);

      if (nameMatch && filenameMatch && contentTypeMatch) {
        // 移除内容末尾的\r\n(避免写入文件时添加冗余字节)
        const cleanContent = contentBuffer.slice(0, contentBuffer.length - 2);
        parsedData[nameMatch[1]] = {
          filename: filenameMatch[1],
          contentType: contentTypeMatch[1],
          contentData: cleanContent,
        };

        // 直接写入Buffer,无需指定编码
        fs.writeFile(filenameMatch[1], cleanContent, (err) => {
          err ? console.error('保存失败:', err) : console.log('文件保存成功');
        });
      }
    } else {
      // 解析普通文本字段
      const nameMatch = headerStr.match(/name="(.+)"/);
      if (nameMatch) {
        parsedData[nameMatch[1]] = contentBuffer.toString('utf8').trim();
      }
    }
  }

  return parsedData;
}

// 辅助函数:用分隔符分割Buffer
function splitBuffer(buffer, separator) {
  const parts = [];
  let start = 0;
  let index;

  while ((index = buffer.indexOf(separator, start)) !== -1) {
    parts.push(buffer.slice(start, index));
    start = index + separator.length;
  }
  parts.push(buffer.slice(start));
  return parts;
}

核心修复说明

  • 用Buffer处理二进制数据:全程避免将文件数据转成字符串,保留原始字节。
  • 精准分割内容:自定义splitBuffer函数分割multipart部分,避免字符串split的编码问题。
  • 清理冗余字符:移除文件内容末尾的\r\n,保证文件结构完整。
  • 直接写入Buffer:fs.writeFile支持直接写入Buffer,自动处理字节,无需指定编码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 07:00:18