WorkerJS_CloudFlare_ImageBed/cloudflare-worker-js-api/API_IMG_s3filebase.js
BlueSkyXN 028f294945 0.9.5
S3兼容的filebase适配测试
2024-09-20 15:31:13 +08:00

272 lines
8.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

addEventListener('fetch', event => {
event.respondWith(handles3filebaseRequest(event.request));
});
async function handles3filebaseRequest(request) {
if (request.method !== 'POST') {
return new Response('Method not allowed', { status: 405 });
}
try {
const formData = await request.formData();
const file = formData.get('image'); // 期待表单字段名为'image'
if (!file) {
return new Response('No file uploaded', { status: 400 });
}
// 将文件内容读取为ArrayBuffer
const fileContent = await file.arrayBuffer();
// 从环境变量中获取s3filebase_key并解析出bucket_name、access_key和secret_key
const s3filebaseKey = S3FILEBASE_KEY; // S3FILEBASE_KEY是您的环境变量
const [bucketName, accessKeyId, secretAccessKey] = s3filebaseKey.split('|');
// 检查是否成功解析
if (!bucketName || !accessKeyId || !secretAccessKey) {
console.error('Failed to parse S3FILEBASE_KEY environment variable.');
return new Response('Server configuration error.', { status: 500 });
}
const region = 'us-east-1'; // Filebase默认使用'us-east-1'
const service = 's3';
const host = 's3.filebase.com';
// 生成带时间戳的文件名
const fileName = file.name || 'upload';
const timestamp = new Date().toISOString().replace(/[:\-]|\.\d{3}/g, '');
const s3FileKey = `${fileName}_${timestamp}`;
// 准备请求细节
const method = 'PUT';
const canonicalUri = `/${bucketName}/${s3FileKey}`;
const canonicalQueryString = '';
const payloadHash = await sha256(fileContent);
const amzDate = getAmzDate();
const dateStamp = amzDate.substring(0, 8);
const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
// 准备请求头
let headers = {
Host: host,
'X-Amz-Date': amzDate,
'Content-Type': 'application/octet-stream',
'Content-Length': fileContent.byteLength.toString(),
};
// 创建规范请求
const signedHeaders = getSignedHeaders(headers);
const canonicalHeaders = getCanonicalHeaders(headers);
const canonicalRequest = [
method,
canonicalUri,
canonicalQueryString,
canonicalHeaders,
signedHeaders,
payloadHash,
].join('\n');
// 创建待签名字符串
const canonicalRequestHash = await sha256(canonicalRequest);
const stringToSign = [
'AWS4-HMAC-SHA256',
amzDate,
credentialScope,
canonicalRequestHash,
].join('\n');
// 计算签名
const signingKey = await getSignatureKey(secretAccessKey, dateStamp, region, service);
const signature = await hmacHex(signingKey, stringToSign);
// 添加授权头
headers['Authorization'] = [
`AWS4-HMAC-SHA256 Credential=${accessKeyId}/${credentialScope}`,
`SignedHeaders=${signedHeaders}`,
`Signature=${signature}`,
].join(', ');
// 发起PUT请求上传文件
const url = `https://${host}${canonicalUri}`;
const uploadResponse = await fetch(url, {
method: method,
headers: headers,
body: fileContent,
});
if (!uploadResponse.ok) {
const errorText = await uploadResponse.text();
console.error(`上传失败: ${uploadResponse.status} - ${errorText}`);
return new Response(`Upload failed with status: ${uploadResponse.status}`, { status: uploadResponse.status });
}
console.log('文件上传成功!');
// 现在获取元数据以获得CID
const metadataResponse = await getObjectMetadata(
accessKeyId,
secretAccessKey,
bucketName,
s3FileKey,
region,
service,
host
);
if (!metadataResponse.ok) {
const errorText = await metadataResponse.text();
console.error(`获取元数据失败: ${metadataResponse.status} - ${errorText}`);
return new Response(`Failed to retrieve metadata with status: ${metadataResponse.status}`, { status: metadataResponse.status });
}
// 从元数据中提取CID
const cid = metadataResponse.headers.get('x-amz-meta-cid');
if (!cid) {
console.error('在元数据中未找到CID。');
return new Response('CID not found in metadata.', { status: 500 });
}
console.log(`CID: ${cid}`);
// 构建访问URL
const accessUrl = `https://ipfs.filebase.io/ipfs/${cid}`;
// 返回访问URL
return new Response(accessUrl, {
status: 200,
headers: { 'Content-Type': 'text/plain' },
});
} catch (error) {
console.error('Error:', error);
return new Response('Internal Server Error', { status: 500 });
}
}
// 辅助函数
function getAmzDate() {
const now = new Date();
return now.toISOString().replace(/[:-]|\.\d{3}/g, '');
}
function getSignedHeaders(headers) {
return Object.keys(headers)
.map(key => key.toLowerCase())
.sort()
.join(';');
}
function getCanonicalHeaders(headers) {
return Object.keys(headers)
.map(key => key.toLowerCase() + ':' + headers[key].trim() + '\n')
.sort()
.join('');
}
async function sha256(message) {
let buffer;
if (message instanceof ArrayBuffer) {
buffer = message;
} else {
const encoder = new TextEncoder();
buffer = encoder.encode(message);
}
const hashBuffer = await crypto.subtle.digest('SHA-256', buffer);
return arrayBufferToHex(hashBuffer);
}
async function hmac(key, message) {
const cryptoKey = await crypto.subtle.importKey(
'raw',
key,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
const signature = await crypto.subtle.sign('HMAC', cryptoKey, message);
return signature;
}
async function hmacHex(key, message) {
const encoder = new TextEncoder();
const keyData = key;
const messageData = encoder.encode(message);
const signature = await hmac(keyData, messageData);
return arrayBufferToHex(signature);
}
function arrayBufferToHex(buffer) {
const byteArray = new Uint8Array(buffer);
return Array.from(byteArray)
.map(byte => byte.toString(16).padStart(2, '0'))
.join('');
}
async function getSignatureKey(key, dateStamp, regionName, serviceName) {
const kDate = await hmac(encoder.encode('AWS4' + key), encoder.encode(dateStamp));
const kRegion = await hmac(kDate, encoder.encode(regionName));
const kService = await hmac(kRegion, encoder.encode(serviceName));
const kSigning = await hmac(kService, encoder.encode('aws4_request'));
return kSigning;
}
// 获取对象元数据的函数HEAD请求
async function getObjectMetadata(accessKeyId, secretAccessKey, bucketName, objectKey, region, service, host) {
const method = 'HEAD';
const canonicalUri = `/${bucketName}/${objectKey}`;
const canonicalQueryString = '';
const payloadHash = await sha256('');
const amzDate = getAmzDate();
const dateStamp = amzDate.substring(0, 8);
const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
// 准备请求头
let headers = {
Host: host,
'X-Amz-Date': amzDate,
};
// 创建规范请求
const signedHeaders = getSignedHeaders(headers);
const canonicalHeaders = getCanonicalHeaders(headers);
const canonicalRequest = [
method,
canonicalUri,
canonicalQueryString,
canonicalHeaders,
signedHeaders,
payloadHash,
].join('\n');
// 创建待签名字符串
const canonicalRequestHash = await sha256(canonicalRequest);
const stringToSign = [
'AWS4-HMAC-SHA256',
amzDate,
credentialScope,
canonicalRequestHash,
].join('\n');
// 计算签名
const signingKey = await getSignatureKey(secretAccessKey, dateStamp, region, service);
const signature = await hmacHex(signingKey, stringToSign);
// 添加授权头
headers['Authorization'] = [
`AWS4-HMAC-SHA256 Credential=${accessKeyId}/${credentialScope}`,
`SignedHeaders=${signedHeaders}`,
`Signature=${signature}`,
].join(', ');
// 发起HEAD请求
const url = `https://${host}${canonicalUri}`;
const response = await fetch(url, {
method: method,
headers: headers,
});
return response;
}
// TextEncoder实例
const encoder = new TextEncoder();