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

Remix应用表单上传图片至S3成功但文件损坏无法打开

Remix应用表单上传图片至S3成功但文件损坏无法打开

我之前也碰到过几乎一模一样的问题!看了你的代码,核心问题出在Uint8Array的拼接逻辑上——你每次调用uInt8Array.set(x)时,都是从索引0开始写入数据,后面的数组段会直接覆盖前面的内容,最后得到的文件其实只是最后一段Uint8Array重复填充到对应长度的结果,自然无法被识别为正常图片。

先给你修复拼接逻辑的方案

修改你的Uint8Array合并代码,维护一个偏移量变量,确保每一段数据都写到正确的位置:

async ({ name, contentType, data, filename }) => {
  const arrayOfUInt8Array: Uint8Array[] = [];
  let length = 0;
  for await (const x of data) {
    arrayOfUInt8Array.push(x);
    length += x.length;
  }

  const uInt8Array = new Uint8Array(length);
  let offset = 0; // 新增偏移量变量,记录当前写入位置
  for (const x of arrayOfUInt8Array) {
    uInt8Array.set(x, offset); // 传入偏移量,写入到正确位置
    offset += x.length; // 更新偏移量
  }

  const uploadCommand = new Upload({
    client: s3Client,
    params: {
      Bucket: s3Bucket,
      Key: filename,
      Body: uInt8Array,
      ContentType: contentType,
    }
  });

  await uploadCommand.done();
  return '';
},

更简洁的优化方案:直接使用AsyncIterable

其实S3 SDK v3原生支持AsyncIterable<Uint8Array>作为请求Body,完全不用手动拼接成单个Uint8Array,这样既避免了拼接错误,还能节省内存(大文件不用全部加载到内存中)。你可以把代码简化成这样:

async ({ name, contentType, data, filename }) => {
  const uploadCommand = new Upload({
    client: s3Client,
    params: {
      Bucket: s3Bucket,
      Key: filename,
      Body: data, // 直接传入data这个AsyncIterable对象
      ContentType: contentType,
    }
  });

  await uploadCommand.done();
  return '';
},

额外检查点

最后再确认两个细节:

  • 确保contentType是正确的(比如image/png、image/jpeg),如果类型标记错误,浏览器也会无法识别图片
  • 上传到S3的文件权限设置正常(比如开启公共读或者你有对应的访问权限),不过你已经能下载文件,这个大概率没问题

备注:内容来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 16:33:03