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
相关产品推荐
相关产品推荐

