使用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": "***" }
解决方案
核心问题分析
- XAmzContentSHA256Mismatch:
- 手动构造的
X-Amz-Content-SHA256格式错误,S3协议要求该值为原始二进制哈希的base64编码,而非hex(xxx)格式; - multer字段名与客户端FormData不匹配(服务端用
file,客户端传myFile),导致未正确获取文件,错误使用req.body.myFile计算哈希和上传。
- 手动构造的
- 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
相关产品推荐
相关产品推荐

