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

JavaScript生成的S3 ManagedUpload的CheckSumSHA256始终无效问题求助

Amazon S3 ManagedUpload的CheckSumSHA256始终无效的排查与解决

我在用JavaScript实现Amazon S3 ManagedUpload时,生成的CheckSumSHA256始终无效。先计算文件的SHA256哈希值,再用btoa(sha256)转成base64编码,但一直收到错误:InvalidRequest: Value for x-amz-checksum-sha256 header is invalid.

AWS文档说明:

ChecksumSHA256 — (String) 对象经过base64编码的256位SHA-256摘要,仅在随对象上传时存在。对于分段上传,该值可能不是对象的校验和。有关分段上传校验和计算的更多信息,请参阅《Amazon S3用户指南》中的“检查对象完整性”。

当前上传参数代码:

let sha256conv = btoa(sha256);

const params = {
        Bucket: process.env.BUCKET,
        Key: path.basename(task.file),
        Body: fileData,
        ContentType: ContentType || 'application/octet-stream',
        CacheControl: "max-age=172800",
        ChecksumAlgorithm: 'sha256',
        ChecksumSHA256: sha256conv
    };

const upload = new AWS.S3.ManagedUpload({
        service: s3,
        params
    });

SHA256生成函数:

export async function getFileSha256(fileName, fileSize, onProgress) {
    return new Promise((resolve, reject) => {
        const hash = crypto.createHash('sha256');

// change to 'binary' if you want a binary hash.
        hash.setEncoding('hex');
        const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
        bar1.start(fileSize, 0);

        const fd = fs.createReadStream(fileName);

        fd.on('data', async chunk => {
            let processedBytes = bar1.value + chunk.length;
            bar1.update(processedBytes);
            await onProgress(processedBytes)
        })

        fd.on('end', function () {
            bar1.stop();
            hash.end();
            return resolve(hash.read())
        });

// read all file and pipe it (write it) to the hash object
        fd.pipe(hash);
    });
}

问题原因

  1. 哈希编码格式错配:生成函数中hash.setEncoding('hex')输出的是十六进制字符串,而AWS要求的是原始二进制SHA256摘要的base64编码。直接对十六进制字符串用btoa()转码,得到的结果不符合S3的校验规则。
  2. btoa()的使用场景错误:btoa()仅能处理ASCII字符串,对十六进制字符串转码无法得到原始二进制数据的base64结果。

解决方法

方案一:修改哈希生成逻辑(推荐)

直接生成二进制哈希值并转base64,无需额外转换:

export async function getFileSha256(fileName, fileSize, onProgress) {
    return new Promise((resolve, reject) => {
        const hash = crypto.createHash('sha256');
        // 移除hex编码设置,保留原始二进制
        const bar1 = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);
        bar1.start(fileSize, 0);

        const fd = fs.createReadStream(fileName);

        fd.on('data', async chunk => {
            let processedBytes = bar1.value + chunk.length;
            bar1.update(processedBytes);
            await onProgress(processedBytes);
        });

        fd.on('end', function () {
            bar1.stop();
            hash.end();
            // 读取二进制哈希并转base64
            const buffer = hash.read();
            resolve(buffer.toString('base64'));
        });

        fd.pipe(hash);
    });
}

上传时直接使用返回结果,无需btoa():

const sha256conv = await getFileSha256(task.file, fileSize, onProgress);

const params = {
        Bucket: process.env.BUCKET,
        Key: path.basename(task.file),
        Body: fileData,
        ContentType: ContentType || 'application/octet-stream',
        CacheControl: "max-age=172800",
        ChecksumAlgorithm: 'sha256',
        ChecksumSHA256: sha256conv
    };

方案二:保留十六进制生成逻辑,转换方式修正

如果不想修改哈希生成函数,将十六进制字符串转成二进制Buffer后再转base64:

// 替换原有的btoa(sha256)
const sha256Buffer = Buffer.from(sha256, 'hex');
const sha256conv = sha256Buffer.toString('base64');

额外注意事项

  • 确保fileData与计算哈希时读取的文件内容完全一致,避免因文件读取编码、分段方式差异导致哈希不匹配。
  • 若使用ManagedUpload的分段上传,S3可能不会将你提供的ChecksumSHA256作为对象最终校验和,需参考S3文档中分段上传的校验和计算规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 23:57:27