Files
Cloudflare-fileshare/main.js
2025-05-27 13:23:47 +08:00

181 lines
5.6 KiB
JavaScript
Executable File
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.

export default {
async fetch(request, env) {
const url = new URL(request.url);
const path = url.pathname.split('/');
// 处理CORS
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
}
});
}
// 文件上传
if (path[1] === 'upload' && request.method === 'POST') {
try {
const formData = await request.formData();
const file = formData.get('file');
const password = formData.get('password') || null;
const expiresAt = formData.get('expires') ? new Date(formData.get('expires')) : null;
if (!file) {
return new Response(JSON.stringify({ error: 'No file provided' }), {
status: 400,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
// 生成唯一文件ID
const fileId = crypto.randomUUID();
// 上传文件到R2将 FILES_BUCKET 改为 file_share_bucket
await env.file_share_bucket.put(fileId, file);
// 存储文件元数据到D1
await env.DB.prepare(
'INSERT INTO files (id, name, type, size, password, created_at, expires_at) VALUES (?, ?, ?, ?, ?, ?, ?)'
).bind(
fileId,
file.name,
file.type,
file.size,
password,
new Date().toISOString(),
expiresAt ? expiresAt.toISOString() : null
).run();
return new Response(JSON.stringify({
success: true,
fileId: fileId,
url: `${url.origin}/file/${fileId}`
}), {
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
}
// 文件下载
if (path[1] === 'file' && path[2]) {
const fileId = path[2];
const password = url.searchParams.get('password') || null;
try {
// 获取文件元数据
const fileInfo = await env.DB.prepare(
'SELECT * FROM files WHERE id = ?'
).bind(fileId).first();
if (!fileInfo) {
return new Response(JSON.stringify({ error: 'File not found' }), {
status: 404,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
// 检查文件是否过期
if (fileInfo.expires_at && new Date(fileInfo.expires_at) < new Date()) {
return new Response(JSON.stringify({ error: 'File has expired' }), {
status: 410,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
// 检查密码
if (fileInfo.password && fileInfo.password !== password) {
return new Response(JSON.stringify({ error: 'Invalid password' }), {
status: 401,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
// 从R2获取文件将 FILES_BUCKET 改为 file_share_bucket
const file = await env.file_share_bucket.get(fileId);
if (!file) {
return new Response(JSON.stringify({ error: 'File not found in storage' }), {
status: 404,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
// 更新下载计数
await env.DB.prepare(
'UPDATE files SET downloads = downloads + 1 WHERE id = ?'
).bind(fileId).run();
// 返回文件
return new Response(file.body, {
headers: {
'Content-Type': file.httpMetadata.contentType || 'application/octet-stream',
'Content-Disposition': `attachment; filename="${fileInfo.name}"`,
'Access-Control-Allow-Origin': '*'
}
});
} catch (error) {
return new Response(JSON.stringify({ error: error.message }), {
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
}
});
}
}
// 修改默认响应
const apiDoc = {
message: "\u26a0\ufe0f \u8fd9\u662fAPI\u4e13\u7528\u7aef\u53e3\uff0c\u7981\u6b62\u76f4\u63a5\u8bbf\u95ee",
description: "\u8fd9\u662f\u4e00\u4e2a\u6587\u4ef6\u5b58\u50a8\u548c\u5206\u4eab\u7cfb\u7edf\u7684API\u670d\u52a1",
frontend: "<你的前端地址>",
api_endpoints: {
upload: {
method: "POST",
path: "/upload",
description: "\u4e0a\u4f20\u6587\u4ef6"
},
download: {
method: "GET",
path: "/file/:fileId",
description: "\u4e0b\u8f7d\u6587\u4ef6"
}
}
};
return new Response(JSON.stringify(apiDoc, null, 2), {
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Access-Control-Allow-Origin': '*'
}
});
}
};