我正在学习 cloudflare 工作者,我需要通过数字海洋将对象存储在空间中。
如果您不知道,cloudflare worker 不能使用常规的aws-sdk
js 库,因为它使用XMLHttpRequest
了 worker 的隔离区不可用的库。
我正在使用空间 API 进行手动 PUT,并且可以毫无问题地将纯文本对象上传到存储桶。
当我尝试使用构造函数放置图像时,问题就开始了new Buffer.from(...some image content as base64...,'base64')
,我从空间 API 得到的错误是XAmzContentSHA256Mismatch
,我认为问题是当我将正文散列到sha256
使用crypto-js
库时,但我不知道为什么。
import sha256 from 'crypto-js/sha256'
import hmacSha256 from 'crypto-js/hmac-sha256'
export default class SpacesClient {
constructor( config ){
this.accessKey = config.accessKey;
this.secretKey = config.secretKey;
this.region = config.region;
this.domain = config.domain || 'digitaloceanspaces.com';
}
getSignatureKey(key, dateStamp, regionName, serviceName) {
let keyDate = hmacSha256(dateStamp, "AWS4" + key);
let keyRegion = hmacSha256(regionName, keyDate);
let keyService = hmacSha256(serviceName, keyRegion);
return hmacSha256("aws4_request", keyService);
}
//TODO: everything works great if body is text, the next step is to check why it doesn't work when it is Buffer
signAndSendRequest( { method , bucket , path , body , acl , contentType } ){
const amzdate = new Date().toISOString().replace(/[:-]|\.\d{3}/g, '');
const datestamp = amzdate.slice(0, 8)
const service = 's3';
const host = (this.domain !== 'digitaloceanspaces.com')
? `${bucket}.${service}.${this.region}.${this.domain}`
: `${bucket}.${this.region}.${this.domain}`
const endpoint = `https://${host}${path}`;
acl = acl === 'public-read' ? 'public-read' : 'private';
const canonicalUri = path;
const canonicalQuerystring = '';
const payloadHash = sha256(body).toString();
const canonicalHeaders = `content-type:${contentType}\nhost:${host}\nx-amz-acl:${acl}\nx-amz-content-sha256:${payloadHash}\nx-amz-date:${amzdate}\n`;
const signedHeaders = 'content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date';
const algorithm = 'AWS4-HMAC-SHA256';
const canonicalRequest = `${method}\n${canonicalUri}\n${canonicalQuerystring}\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}`;
const credentialScope = `${datestamp}/${this.region}/${service}/aws4_request`;
const stringToSign = `${algorithm}\n${amzdate}\n${credentialScope}\n${sha256(canonicalRequest)}`;
const signingKey = this.getSignatureKey(this.secretKey, datestamp, this.region, service);
const signature = hmacSha256(stringToSign, signingKey);
const authorizationHeader = `${algorithm} Credential=${this.accessKey}/${credentialScope},SignedHeaders=${signedHeaders},Signature=${signature}`;
const params = {
method: method,
headers: {
'Authorization': authorizationHeader,
'content-type': contentType,
'x-amz-acl': acl,
'x-amz-content-sha256': payloadHash,
'x-amz-date': amzdate,
},
};
if ( body ) params.body = body;
return fetch( endpoint, params );
}
getObject( params ) {
return this.signAndSendRequest( { method: 'GET' , ...params } );
}
putObject(params) {
return this.signAndSendRequest( { method: 'PUT' , ...params } );
}
deleteObject(params) {
return this.signAndSendRequest( { method: 'DELETE' , ...params } );
}
}
当 body 变量是字符串并且 contentType 是时,它的效果很好text/plain
,
任何帮助,将不胜感激。