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

Serverless Framework:上传至S3的二进制文件损坏问题

解决Busboy解析后S3上传二进制文件损坏的问题

我之前在做Serverless+S3上传的时候也踩过这个坑,二进制文件损坏大概率是编码处理或者API Gateway的配置问题,结合你的代码场景,给你几个靠谱的解决方案:

解决方案1:配置API Gateway支持二进制数据

这是最常见的原因——如果没配置API Gateway的二进制媒体类型,它会把所有请求体当成UTF-8文本处理,直接破坏二进制文件的字节结构。

在你的serverless.yml里添加以下配置:

provider:
  apiGateway:
    binaryMediaTypes:
      - '*/*' # 或者更精确地指定你需要的类型,比如image/*, application/pdf, text/plain

配置后重新部署服务,API Gateway就会正确传递二进制数据,不会做额外的编码转换。

解决方案2:改用流式上传到S3(推荐)

手动拼接Buffer不仅容易出编码问题,还会占用更多内存(尤其是大文件)。直接把Busboy的文件流传给S3的上传接口,能从根源避免这类问题:

const AWS = require('aws-sdk');
const s3 = new AWS.S3();
const Busboy = require('busboy');

// 处理请求的核心逻辑
exports.handler = async (event) => {
  return new Promise((resolve, reject) => {
    const busboy = new Busboy({ headers: event.headers });
    
    busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
      // 直接将Busboy的文件流作为S3上传的Body
      const uploadParams = {
        Bucket: '你的S3桶名称',
        Key: filename,
        Body: file,
        ContentType: mimetype
      };

      s3.upload(uploadParams, (err, data) => {
        if (err) {
          console.error('上传失败:', err);
          reject({ statusCode: 500, body: '上传失败' });
        } else {
          console.log('上传成功:', data.Location);
          resolve({ statusCode: 200, body: JSON.stringify({ url: data.Location }) });
        }
      });
    });

    // 处理Base64编码的请求体
    let body = event.body;
    if (event.isBase64Encoded) {
      // 清理Base64中的换行/空格(部分网关可能会自动添加)
      body = body.replace(/\s/g, '');
    }
    busboy.write(body, event.isBase64Encoded ? 'base64' : 'binary');
    busboy.end();
  });
};

这种流式处理的方式既高效又能避免Buffer拼接可能带来的编码错误。

解决方案3:修正Buffer拼接的预处理逻辑

如果你坚持要手动拼接Buffer,需要确保Base64数据的预处理是正确的:

let buffers = [];
file.on('data', data => {
  // 确保每个chunk都是Buffer类型(避免意外的字符串转换)
  if (typeof data === 'string') {
    buffers.push(Buffer.from(data, 'binary'));
  } else {
    buffers.push(data);
  }
});
file.on('end', () => {
  result.filename = filename;
  result.contentType = mimetype;
  // 拼接Buffer时指定编码(如果需要)
  result.file = Buffer.concat(buffers);
});

// 预处理请求体
let body = event.body;
if (event.isBase64Encoded) {
  body = body.replace(/\s/g, ''); // 去除Base64中的空白字符
}
busboy.write(body, event.isBase64Encoded ? 'base64' : 'binary');

这里的关键是清理Base64中的空白字符,并且确保每个数据块都是Buffer类型,避免字符串编码转换破坏二进制数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 07:19:57