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

Node.js上传JPG至Tomcat文件内容异常,字节编码遭篡改求助

问题分析与解决方案

你遇到的问题核心是二进制文件在构建请求体时被错误地转换为UTF-8字符串,导致所有无法被UTF-8解析的字节(最高位为1的单字节)被替换成了UTF-8的替换字符�(编码为EF BF BD),最终上传的文件内容被篡改。

问题根源

你的代码中直接将fs.readFileSync返回的Buffer(二进制文件内容)与字符串进行拼接:

var content = "--"+boundary+"\r\n" + 
  "Content-Disposition: form-data; name=\"file\"; filename=\"image.jpg\"\r\n" + 
  "Content-Type: application/octet-stream\r\n" + 
  "Content-Transfer-Encoding: BINARY\r\n" + 
  "\r\n" + 
  fContent + "\r\n" +  // 这里把Buffer转成了UTF-8字符串
  "--"+boundary+"--\r\n"

当Node.js将Buffer与字符串拼接时,会自动调用Buffer.toString('utf8')进行转换。而二进制图片中存在大量不符合UTF-8编码规则的字节(比如最高位为1的单字节),这些字节会被替换成�,对应UTF-8的三个字节EF BF BD,这就是你看到的文件内容篡改现象。

修复方案

要解决这个问题,必须避免将二进制Buffer转换为字符串,而是将所有请求体部分都转换为Buffer,再用Buffer.concat合并成一个完整的请求体。具体修改如下:

  1. 将所有字符串部分转换为Buffer
  2. 用Buffer.concat合并所有Buffer片段
  3. 正确计算Content-Length为合并后Buffer的长度

修改后的Node.js代码:

var agentOptions; 
var agent; 
agentOptions = { 
  host: 'this.is.my.server', 
  port: '8443', 
  path: '/', 
  rejectUnauthorized: false 
}; 
agent = new https.Agent(agentOptions); 

var binaryFilename = "image.jpg"; 
var fContent = fs.readFileSync(binaryFilename); 
console.log( "file size = " + fContent.length ); 

var boundary = '69b2c2b9c464731d';

// 将所有字符串部分转为Buffer
var part1 = Buffer.from(`--${boundary}\r\n`);
var part2 = Buffer.from(`Content-Disposition: form-data; name="file"; filename="image.jpg"\r\n`);
var part3 = Buffer.from(`Content-Type: application/octet-stream\r\n`);
var part4 = Buffer.from(`Content-Transfer-Encoding: BINARY\r\n\r\n`);
var part5 = fContent; // 保持原Buffer
var part6 = Buffer.from(`\r\n--${boundary}--\r\n`);

// 合并所有Buffer片段
var content = Buffer.concat([part1, part2, part3, part4, part5, part6]);

postOptions = { 
  headers: { 
    'Content-Type': `multipart/form-data; boundary=${boundary}`, 
    'Content-Length': content.length, // 使用合并后Buffer的长度
    'Authorization': 'Basic ABCEDFE..' 
  }, 
  host: 'this.is.my.server', 
  port: '8443', 
  path: '/restservices/uploadimage?data=value&data2=value2', 
  method: 'POST', 
  strictSSL: false, 
  agent: agent 
}; 

// Set up the request 
post_req = https.request(postOptions, function(res) { 
  // res.setEncoding('utf8') ; // 不要设置utf8编码,避免响应解析错误(如果响应是二进制的话)
  res.on('data', function (chunk) { 
    console.log('Response: ' + chunk); 
  }); 
}); 

// post the data 
post_req.write(content); 
post_req.end(); 

额外排查建议

  • 验证请求体编码:永远不要将二进制数据转换为UTF-8字符串传输,必须保持Buffer格式。
  • 检查Content-Length:错误的Content-Length可能导致服务器截断或错误解析请求体,确保其值等于实际发送的字节数。
  • 服务器端验证:虽然你的服务器代码使用MultipartFile看起来没问题,但可以在服务器端打印上传文件的字节数,确认是否与客户端发送的一致,排除服务器端的编码问题。
  • 避免设置响应编码:如果服务器返回的是二进制数据,不要调用res.setEncoding('utf8'),否则会同样导致响应内容被错误转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:44:24