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

使用s3Client向DigitalOcean Spaces传图片遇XAmzContentSHA256Mismatch错误求助

问题描述

尝试将图片上传至DigitalOcean Spaces,客户端通过FormData提交,服务端基于Next.js开发,但遇到两个错误:XAmzContentSHA256Mismatch和MissingContentLength。

客户端代码

const formData = new FormData();
formData.append('myFile', file as string)
fetch('/api/upload',
        {
        method: 'POST',
        body: formData
        }).then(response => {
            console.log(`response sucess: ${response.status}`)
        }).catch(error => {
            console.log(error)
            // Handle error
});

服务端代码(Next.js API)

export default async function upload(req: NextApiRequest & { [key: string]: any }, res: NextApiResponse) {
    const multerUpload = multer({ dest: "uploads/" });
    await runMiddleware(req, res, multerUpload.single("file"));
    const file = req.body.myFile;
    const { bucket, key, fileName } = req.body;
    const contentHash = crypto.createHash('sha256').update(file).digest('hex');
    const content_length = getBytesForContentLength(file)
    const bucketParams = {
        Bucket: bucket,
        Key: key,
        Body: file,
        ContentType: getImageType(file),
        ContentLength: content_length, 
        Headers: {
          'X-Amz-Content-SHA256': `hex(${contentHash})`
      }
    };
    try {
        const response = await s3Client.send(new PutObjectCommand(bucketParams));
        console.log(response.$metadata);
        console.log("Success");

        //todo: if successful, post the path to the server DB

        res.status(200)

        
    } catch (err) {
        console.log("Error", err);
        res.status(500).send("Server Error");
    }
}

辅助函数

runMiddleware与API配置

function runMiddleware(req: NextApiRequest & {[key: string]: any}, res: NextApiResponse, fn: (...args: any[]) => void): Promise<any> {
    return new Promise((resolve, reject) => {
      fn(req, res, (result: any) => {
        if (result instanceof Error) {
          return reject(result);
        }
  
        return resolve(result);
      });
    });
  }
  
  export const config = {
    api: {
      bodyParser: false,
    },
};

getBytesForContentLength

function getBytesForContentLength(base64String: string): number {
    // assume that file_str is the base64 encoded file string
    const myBuffer = Buffer.from(base64String, 'base64');
    return myBuffer.byteLength
}

错误信息

XAmzContentSHA256Mismatch

{
  "$fault": "client",
  "$metadata": {
    "httpStatusCode": 400,
    "requestId": "***",
    "extendedRequestId": undefined,
    "cfId": undefined,
    "attempts": 1,
    "totalRetryDelay": 0
  },
  "Code": "XAmzContentSHA256Mismatch",
  "BucketName": "***",
  "RequestId": "***",
  "HostId": "***"
}

MissingContentLength

{
  "Code": "MissingContentLength",
  "BucketName": "***",
  "RequestId": "***",
  "HostId": "***"
}

解决方案

核心问题分析

  1. XAmzContentSHA256Mismatch:
    • 手动构造的X-Amz-Content-SHA256格式错误,S3协议要求该值为原始二进制哈希的base64编码,而非hex(xxx)格式;
    • multer字段名与客户端FormData不匹配(服务端用file,客户端传myFile),导致未正确获取文件,错误使用req.body.myFile计算哈希和上传。
  2. MissingContentLength:
    • 上传字符串类型Body时SDK无法自动计算长度,需手动设置;但使用Buffer类型Body时,SDK可自动处理该参数。

具体修复步骤

1. 客户端与服务端字段名统一

修改客户端代码,将FormData字段名改为file,与服务端multer配置匹配:

const formData = new FormData();
formData.append('file', file); // 直接传入File对象,无需as string
fetch('/api/upload', {
  method: 'POST',
  body: formData
}).then(response => {
  console.log(`response success: ${response.status}`)
}).catch(error => {
  console.log(error)
});

2. 服务端正确处理文件

调整服务端代码,使用multer返回的req.file获取文件,用Buffer上传并修正哈希计算:

import fs from 'fs';

export default async function upload(req: NextApiRequest & { file?: Express.Multer.File }, res: NextApiResponse) {
  // 配置multer使用内存存储,避免本地临时文件
  const storage = multer.memoryStorage();
  const multerUpload = multer({ storage: storage });
  await runMiddleware(req, res, multerUpload.single("file"));

  if (!req.file) {
    return res.status(400).send("No file uploaded");
  }

  const { bucket, key } = req.body;
  const fileBuffer = req.file.buffer;
  
  // 计算符合S3要求的base64格式SHA256哈希
  const contentHash = crypto.createHash('sha256').update(fileBuffer).digest('base64');
  
  const bucketParams = {
    Bucket: bucket,
    Key: key,
    Body: fileBuffer,
    ContentType: req.file.mimetype, // 直接使用multer获取的MIME类型
    Headers: {
      'X-Amz-Content-SHA256': contentHash
    }
  };

  try {
    const response = await s3Client.send(new PutObjectCommand(bucketParams));
    console.log(response.$metadata);
    console.log("Success");

    res.status(200).send("Upload successful");
  } catch (err) {
    console.log("Error", err);
    res.status(500).send("Server Error");
  }
}

3. 清理冗余代码

删除getBytesForContentLength函数,因为使用Buffer作为Body时,SDK会自动计算ContentLength,无需手动设置。

关键注意事项

  • DigitalOcean Spaces兼容S3协议,严格遵循AWS SDK签名规则即可,无需手动构造不符合规范的请求头;
  • 优先使用Buffer类型作为上传Body,SDK会自动处理ContentLength和哈希计算;
  • 确保multer的字段名与客户端FormData的字段名完全一致,否则无法正确解析文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 07:54:55