Cloudflare R2当网盘！Workers+R2无服务器部署！

WARNING：R2 免费容量是 10G，Workers 免费访问限制是每日 100 万次，很容易被刷流量，请为你绑定的域名设置速率限制等限制手段以避免睡一晚上成为百万负翁

创建一个 R2 存储桶

不教了，简单的雅痞。可见创建 R2 存储桶

将 R2 与 Workers 连接起来

不教了，简单的雅痞。可见创建 Workers，连接 R2

将 Workers 代码改为如下，设置一个目录单独存放要公开的文件，这里是guest。代码内嵌了 HTML，可自行更改：

Copy
export default {
async fetch(request, env, ctx) {
const bucket = env.MY_BUCKET;
const rootDirectory = 'guest/';
const url = new URL(request.url);

// Helper function to get the current directory
const getCurrentDirectory = (path) => {
const cleanPath = path.replace(/^\/+|\/+$/g, '');
return rootDirectory + cleanPath + (cleanPath ? '/' : '');
};

// Helper function to get parent directory
const getParentDirectory = (path) => {
const parts = path.split('/').filter(p => p);
parts.pop();
return '/' + parts.join('/');
};

// List files and folders in the current directory
async function listDirectory(directory) {
const objects = await bucket.list({ prefix: directory, delimiter: '/' });
const items = new Set();

for (const obj of objects.objects) {
const relativePath = obj.key.slice(directory.length);
if (relativePath) {
items.add(relativePath.split('/')[0]);
}
}

for (const prefix of objects.delimitedPrefixes) {
const relativePath = prefix.slice(directory.length);
if (relativePath) {
items.add(relativePath.split('/')[0]);
}
}

return Array.from(items).sort();
}

// Handle directory listing
if (!url.pathname.startsWith('/download/')) {
const currentDirectory = getCurrentDirectory(url.pathname);
try {
const items = await listDirectory(currentDirectory);

let html = `





AcoFork R2 Files

body, html {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
line-height: 1.6;
height: 100%;
}
body {
background-image: url('https://hrandom.onani.cn');
background-size: cover;
background-position: center;
background-attachment: fixed;
display: flex;
justify-content: center;
align-items: center;
}
.container {
width: 80%;
max-width: 800px;
margin: 40px;
padding: 30px;
background-color: rgba(255, 255, 255, 0.5);
backdrop-filter: blur(10px);
border-radius: 15px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
h1 {
color: #333;
text-align: center;
margin-bottom: 30px;
}
ul {
list-style-type: none;
padding: 0;
margin: 0;
}
li {
margin-bottom: 10px;
border: 1px solid rgba(0, 0, 0, 0.1);
border-radius: 8px;
overflow: hidden;
transition: all 0.3s ease;
}
li:hover {
transform: translateY(-3px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
a {
display: block;
padding: 12px 15px;
text-decoration: none;
color: #333;
transition: background-color 0.3s ease;
}
a:hover {
background-color: rgba(255, 255, 255, 0.5);
}
.folder::before {
content: "📁 ";
color: #FFA500;
}
.file::before {
content: "📄 ";
color: #008000;
}
.parent-link {
display: inline-block;
margin-bottom: 20px;
padding: 8px 15px;
background-color: rgba(0, 102, 204, 0.8);
color: white;
text-decoration: none;
border-radius: 5px;
transition: background-color 0.3s ease;
}
.parent-link:hover {
background-color: rgba(0, 82, 163, 0.9);
}
@keyframes clickEffect {
0% { transform: scale(1); }
50% { transform: scale(0.95); }
100% { transform: scale(1); }
}
.click-effect {
animation: clickEffect 0.3s;
}




我的 R2 Files
`;

// Add parent directory link if not in root
if (currentDirectory !== rootDirectory) {
const parentDir = getParentDirectory(url.pathname);
html += `&larr; Parent Directory`;
}

html += ' ';
for (const item of items) {
const itemPath = currentDirectory.slice(rootDirectory.length) + item;
const isFolder = !item.includes('.');
const className = isFolder ? 'folder' : 'file';

// Update href for files to use the external download URL
const href = isFolder
? `/${encodeURIComponent(itemPath)}`
: `https://r2-dl.afo.im/guest/${encodeURIComponent(itemPath)}`;

html += ` this.classList.remove('click-effect'), 300);">${item}${isFolder ? '/' : ''} `;
}
html += `



document.addEventListener('DOMContentLoaded', (event) => {
document.querySelectorAll('a').forEach(link => {
link.addEventListener('click', function(e) {
if (!this.classList.contains('parent-link')) {
e.preventDefault();
this.classList.add('click-effect');
setTimeout(() => {
window.location = this.href;
}, 300);
}
});
});
});


`;

return new Response(html, {
headers: { 'Content-Type': 'text/html; charset=utf-8' },
});
} catch (error) {
console.error('Error listing objects:', error);
return new Response('Error listing objects', { status: 500 });
}
}

// Default response for any other invalid requests
return new Response('Invalid request', { status: 400 });
},
};

如何上传文件见为你的存储桶添加文件