Node.js环境下使用aws-sdk上传图片到S3后仅加载部分内容的问题
问题排查与修复方案
第一步:先确认截断发生的环节
- 不要直接用生成的URL访问文件,先通过S3控制台查看已上传对象的实际大小,或者用AWS CLI将S3上的文件拉到本地与原文件做二进制对比,确认是上传阶段就截断,还是CDN缓存、浏览器网关导致的访问端截断。很多时候同Key重复上传时旧缓存未刷新,会导致看到的预览内容是旧的截断版本,可以换一个新Key(比如
cover-test-xxx.jpg)上传测试,排除缓存影响。
第二步:校验SDK实际收到的上传参数
- 不要只校验本地源文件,在代码中打印实际传给S3的Body长度:
在fs.readFile的回调里添加日志,对比image.length和你本地用ls -l cover.jpg查到的文件大小是否完全一致。很多人跳过这一步,直接认为Buffer是完整的,但实际可能在异步逻辑中被意外截断。 - 如果你之前手动加了
ContentLength参数,不要手动写死数值,直接用文件实际大小赋值:ContentLength: fs.statSync("cover.jpg").size
避免手动填写的长度和实际Buffer长度不匹配,导致SDK按错误的长度截断上传内容。
第三步:解决SDK异步逻辑与配置的常见坑
- 你现有代码用了
async函数,但fs.readFile和s3.upload都是回调式异步逻辑,没有做等待处理,很容易出现进程在上传未完成时就退出的问题,导致内容传一半就终止。 - AWS SDK v2的
s3.upload默认自动分块逻辑在Node.js环境偶尔会出现缓冲区截断,显式指定分块配置可解决这类问题。
修正后的可运行代码示例
const aws = require("aws-sdk") const fs = require("fs/promises") const { infoLogger } = require("./logger") // 初始化S3实例建议放到全局,不要每次调用都重新初始化 aws.config.update({ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, accessKeyId: process.env.AWS_ACCESS_KEY_ID, region: "us-east-2", }) const s3 = new aws.S3() async function uploadCoverImage() { try { // 用promise形式的fs.readFile,配合await保证异步等待 const image = await fs.readFile("cover.jpg") const fileStat = await fs.stat("cover.jpg") console.log(`待上传文件大小:${fileStat.size},Buffer长度:${image.length}`) const params = { Bucket: process.env.BUCKET_NAME, Key: "cover.jpg", Body: image, ACL: "public-read", ContentType: "image/jpeg", // 修正为标准JPG MIME类型 ContentLength: fileStat.size } // 显式指定分块配置,避免自动逻辑导致的截断 const uploadRes = await s3.upload(params, { partSize: 10 * 1024 * 1024, // 按10MB大小分块 queueSize: 1, // 关闭并发分块,降低网络抖动影响 leavePartsOnError: false }).promise() console.log(`上传完成:${JSON.stringify(uploadRes)}`) } catch (error) { infoLogger.error(`上传失败: ${JSON.stringify(error)}`) } } module.exports = uploadCoverImage
注:如果换成流读取的方式,同样需要保证传入的
ContentLength和实际流的总大小完全匹配,否则SDK会提前终止上传。
内容的提问来源于stack exchange,提问作者terroirnoir
相关产品推荐
相关产品推荐

