xChar
·2 months ago

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

创建一个R2存储桶

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

将R2与Workers连接起来

  1. 不教了,简单的雅痞。可见创建 Workers,连接 R2
  2. 将Workers代码改为如下,设置一个目录单独存放要公开的文件,这里是guest。代码内嵌了HTML,可自行更改:
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 = `
          <!DOCTYPE html>
          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>AcoFork R2 Files</title>
            <style>
              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;
              }
            </style>
          </head>
          <body>
            <div class="container">
              <h1>我的 R2 Files</h1>
        `;
        
        // Add parent directory link if not in root
        if (currentDirectory !== rootDirectory) {
          const parentDir = getParentDirectory(url.pathname);
          html += `<a href="${parentDir}" class="parent-link">&larr; Parent Directory</a>`;
        }
        
        html += '<ul>';
        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 += `<li class="${className}"><a href="${href}" onclick="this.classList.add('click-effect'); setTimeout(() => this.classList.remove('click-effect'), 300);">${item}${isFolder ? '/' : ''}</a></li>`;
        }
        html += `
              </ul>
            </div>
            <script>
              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);
                    }
                  });
                });
              });
            </script>
          </body>
          </html>`;
          
        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 });
  },
};
  1. 如何上传文件见为你的存储桶添加文件
Loading comments...