mirror of
https://github.com/ElmGates/Cloudflare-img2url.git
synced 2026-01-12 04:54:55 +08:00
155 lines
4.1 KiB
JavaScript
155 lines
4.1 KiB
JavaScript
/**
|
|
* Cloudflare Worker 图片上传服务
|
|
* 接收 JSON 格式的 base64 编码图片,上传到 R2 存储桶,并返回图片链接
|
|
*/
|
|
|
|
export default {
|
|
async fetch(request, env, ctx) {
|
|
// 只允许 POST 请求
|
|
if (request.method !== 'POST') {
|
|
return new Response('只接受 POST 请求', { status: 405 });
|
|
}
|
|
|
|
try {
|
|
// 获取请求体内容并解析 JSON
|
|
const contentType = request.headers.get('content-type') || '';
|
|
|
|
if (!contentType.includes('application/json')) {
|
|
return new Response(JSON.stringify({
|
|
success: false,
|
|
message: '请求头必须包含 Content-Type: application/json'
|
|
}), {
|
|
status: 400,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
}
|
|
|
|
// 解析 JSON 请求体
|
|
let jsonData;
|
|
try {
|
|
jsonData = await request.json();
|
|
} catch (e) {
|
|
return new Response(JSON.stringify({
|
|
success: false,
|
|
message: '无效的 JSON 格式'
|
|
}), {
|
|
status: 400,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
}
|
|
|
|
// 支持嵌套的 img 对象
|
|
if (jsonData.img) {
|
|
jsonData = jsonData.img;
|
|
}
|
|
|
|
// 检查 JSON 中是否包含必要字段
|
|
if (!jsonData || !jsonData.imageData) {
|
|
return new Response(JSON.stringify({
|
|
success: false,
|
|
message: 'JSON 必须包含 imageData 字段'
|
|
}), {
|
|
status: 400,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
}
|
|
|
|
// 获取图片类型,默认为 jpeg
|
|
const imageType = jsonData.imageType || 'jpeg';
|
|
// 清理 base64 字符串中的换行符和空格
|
|
const imageData = jsonData.imageData.replace(/[\r\n\s]/g, '');
|
|
|
|
// 验证 base64 数据是否有效 (修改后的验证方法)
|
|
if (!isValidBase64(imageData)) {
|
|
return new Response(JSON.stringify({
|
|
success: false,
|
|
message: '请提供有效的 base64 编码数据'
|
|
}), {
|
|
status: 400,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
}
|
|
|
|
// 生成唯一的文件名
|
|
const fileName = generateUniqueFileName(imageType);
|
|
|
|
// 将 base64 解码为二进制数据
|
|
const binaryData = base64ToArrayBuffer(imageData);
|
|
|
|
// 上传到 R2 存储桶
|
|
await env.MY_BUCKET.put(fileName, binaryData, {
|
|
httpMetadata: {
|
|
contentType: `image/${imageType}`,
|
|
},
|
|
});
|
|
|
|
// 构建图片 URL
|
|
const imageUrl = `${env.PUBLIC_URL}/${fileName}`;
|
|
|
|
// 返回成功响应
|
|
return new Response(JSON.stringify({
|
|
success: true,
|
|
url: imageUrl,
|
|
message: '图片上传成功'
|
|
}), {
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
} catch (error) {
|
|
// 处理错误
|
|
console.error('上传过程中出错:', error);
|
|
return new Response(JSON.stringify({
|
|
success: false,
|
|
message: '上传失败: ' + error.message
|
|
}), {
|
|
status: 500,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 检查字符串是否为有效的 base64 编码
|
|
*/
|
|
function isValidBase64(str) {
|
|
try {
|
|
// 检查是否为有效的 base64 字符串
|
|
const base64Regex = /^[A-Za-z0-9+/=]+$/;
|
|
return base64Regex.test(str);
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 生成唯一的文件名
|
|
*/
|
|
function generateUniqueFileName(imageType) {
|
|
const timestamp = Date.now();
|
|
const randomString = Math.random().toString(36).substring(2, 10);
|
|
return `${timestamp}-${randomString}.${imageType}`;
|
|
}
|
|
|
|
/**
|
|
* 将 base64 字符串转换为 ArrayBuffer
|
|
*/
|
|
function base64ToArrayBuffer(base64) {
|
|
const binaryString = atob(base64);
|
|
const bytes = new Uint8Array(binaryString.length);
|
|
for (let i = 0; i < binaryString.length; i++) {
|
|
bytes[i] = binaryString.charCodeAt(i);
|
|
}
|
|
return bytes.buffer;
|
|
} |