banner
AcoFork

AcoFork

LOVETOLOVE

Cloudflare连接Github!代码仓库当网盘!

WARNING:滥用代码仓库(如 Github/GitLab)可能有封号风险!#

基本原理#

Pages 通过 Git 存储库部署,Workers 通过 API Key 访问你的 Github 仓库目录开放查询 API,Pages 读取这个 API,展示文件

实例#

image

创建 Github 仓库#

  1. 不教了,简单的雅痞。网上的教程比我的头发还多
  2. 根目录创建file文件夹,后续的文件上传下载都在这个文件夹
  3. 根目录创建index.html,填写代码:
    更改 Body 的查询 API URL 为你的:
    const response = await fetch('https://file-up.afo.im/list');
    你目前不知道要改成什么,先往下看
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>File List</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      padding: 20px;
    }
    ul {
      list-style-type: none;
      padding: 0;
    }
    li {
      margin: 5px 0;
    }
    a {
      text-decoration: none;
      color: #007bff;
    }
    a:hover {
      text-decoration: underline;
    }
  </style>
</head>
<body>
  <h1>File List</h1>
  <ul id="file-list"></ul>

  <script>
    async function fetchFileList() {
      try {
        const response = await fetch('https://file-up.afo.im/list');
        if (!response.ok) {
          throw new Error('Failed to fetch file list');
        }
        const fileList = await response.text();
        const files = fileList.split('\n').filter(file => file.trim() !== '');
        displayFiles(files);
      } catch (error) {
        console.error('Error fetching file list:', error);
        document.getElementById('file-list').innerHTML = '<li>Error fetching file list</li>';
      }
    }

    function displayFiles(files) {
      const fileListElement = document.getElementById('file-list');
      fileListElement.innerHTML = files.map(file => 
        `<li><a href="/file/${encodeURIComponent(file)}">${file}</a></li>`
      ).join('');
    }

    fetchFileList();
  </script>
</body>
</html>

创建 Workers,开放 API 查询和上传端点#

  1. 不教了,简单的雅痞。可见创建 Workers,连接 R2不用看连接 R2 的部分
  2. 更改 Workers 代码:
addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const url = new URL(request.url)
  const path = url.pathname

  if (path === '/') {
    return addCORSHeaders(showLoginForm())
  } else if (path === '/login') {
    return addCORSHeaders(await handleLogin(request))
  } else if (path === '/upload') {
    return addCORSHeaders(await handleUpload(request))
  } else if (path === '/check-config') {
    return addCORSHeaders(await checkConfig())
  } else if (path === '/list') {
    return addCORSHeaders(await listFiles()) // 允许直接访问 /list,无需授权
  } else {
    return addCORSHeaders(new Response('Not Found', { status: 404 }))
  }
}

function showLoginForm() {
  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Login</title>
    </head>
    <body>
      <h1>Login</h1>
      <form action="/login" method="POST">
        <input type="password" name="password" placeholder="Enter password" required>
        <button type="submit">Login</button>
      </form>
      <p><a href="/check-config">Check server configuration</a></p>
    </body>
    </html>
  `
  return new Response(html, {
    headers: { 'Content-Type': 'text/html' }
  })
}

async function handleLogin(request) {
  const formData = await request.formData()
  const password = formData.get('password')

  if (password === PASSWORD) {
    return showUploadForm()
  } else {
    return new Response('Invalid password', { status: 401 })
  }
}

function showUploadForm() {
  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>File Upload</title>
    </head>
    <body>
      <h1>File Upload</h1>
      <form action="/upload" method="POST" enctype="multipart/form-data">
        <input type="file" name="file" required>
        <button type="submit">Upload</button>
      </form>
    </body>
    </html>
  `
  return new Response(html, {
    headers: { 'Content-Type': 'text/html' }
  })
}

async function handleUpload(request) {
  try {
    const formData = await request.formData()
    const file = formData.get('file')

    if (!file) {
      return new Response('No file uploaded', { status: 400 })
    }

    const content = await file.arrayBuffer()
    const encodedContent = btoa(String.fromCharCode.apply(null, new Uint8Array(content)))

    const githubResponse = await fetch(`https://api.github.com/repos/${GITHUB_REPO}/contents/file/${file.name}`, {
      method: 'PUT',
      headers: {
        'Authorization': `token ${GITHUB_TOKEN}`,
        'Content-Type': 'application/json',
        'User-Agent': 'Cloudflare Worker'
      },
      body: JSON.stringify({
        message: `Upload ${file.name}`,
        content: encodedContent
      })
    })

    if (githubResponse.ok) {
      return new Response('File uploaded successfully', { status: 200 })
    } else {
      const errorData = await githubResponse.text()
      console.error('GitHub API Error:', errorData)
      return new Response(`Failed to upload file: ${errorData}`, { status: 500 })
    }
  } catch (error) {
    console.error('Upload error:', error)
    return new Response(`Error during upload: ${error.message}`, { status: 500 })
  }
}

async function listFiles() {
  try {
    const githubResponse = await fetch(`https://api.github.com/repos/${GITHUB_REPO}/contents/file`, {
      headers: {
        'Authorization': `token ${GITHUB_TOKEN}`,
        'User-Agent': 'Cloudflare Worker'
      }
    })

    if (!githubResponse.ok) {
      const errorData = await githubResponse.text()
      console.error('GitHub API Error:', errorData)
      return new Response(`Failed to fetch file list: ${errorData}`, { status: 500 })
    }

    const files = await githubResponse.json()

    // 将文件名转换为纯文本,一行一个
    const fileNames = files.map(file => file.name).join('\n')

    return new Response(fileNames, {
      headers: { 'Content-Type': 'text/plain' }
    })
  } catch (error) {
    console.error('Error fetching files:', error)
    return new Response(`Error during fetching files: ${error.message}`, { status: 500 })
  }
}

async function checkConfig() {
  let configStatus = 'All configurations are set correctly.'

  if (!PASSWORD) {
    configStatus = 'ERROR: PASSWORD is not set.'
  } else if (!GITHUB_TOKEN) {
    configStatus = 'ERROR: GITHUB_TOKEN is not set.'
  } else if (!GITHUB_REPO) {
    configStatus = 'ERROR: GITHUB_REPO is not set.'
  } else {
    try {
      const response = await fetch(`https://api.github.com/repos/${GITHUB_REPO}`, {
        headers: {
          'Authorization': `token ${GITHUB_TOKEN}`,
          'User-Agent': 'Cloudflare Worker'
        }
      })

      const responseText = await response.text()

      if (!response.ok) {
        try {
          const data = JSON.parse(responseText)
          configStatus = `ERROR: GitHub API returned an error: ${data.message}`
        } catch (jsonError) {
          configStatus = `ERROR: GitHub API returned a non-JSON response. Status: ${response.status}, Body: ${responseText.substring(0, 100)}...`
        }
      } else {
        try {
          JSON.parse(responseText)
          configStatus += ' GitHub connection successful.'
        } catch (jsonError) {
          configStatus = `WARNING: GitHub API returned a non-JSON response, but the connection was successful. Status: ${response.status}, Body: ${responseText.substring(0, 100)}...`
        }
      }
    } catch (error) {
      configStatus = `ERROR: Failed to connect to GitHub API: ${error.message}`
    }
  }

  const html = `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Configuration Check</title>
    </head>
    <body>
      <h1>Configuration Check</h1>
      <p>${configStatus}</p>
      <a href="/">Back to Login</a>
    </body>
    </html>
  `

  return new Response(html, {
    status: 200,
    headers: { 'Content-Type': 'text/html' }
  })
}

// 添加 CORS 头
function addCORSHeaders(response) {
  const headers = new Headers(response.headers)
  headers.set('Access-Control-Allow-Origin', '*')
  headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS')
  headers.set('Access-Control-Allow-Headers', 'Content-Type')

  return new Response(response.body, {
    status: response.status,
    statusText: response.statusText,
    headers
  })
}
  1. 为 Workers 添加变量
    GITHUB_REPO格式为:Github用户名/Github仓库名
    GITHUB_TOKEN格式为:你的Github API Key。需要有仓库(Repository)修改权限
    PASSWORD为访问上传端点的密码,自行设置(更建议使用 Git 上传)
    image

  2. 访问你的自定义域的/list,看看查询 API 是否正常,是否能列出仓库下 file 文件夹下的文件,如

image

  1. 将你的 URL 填入创建 Github 仓库的第三步中的

const response = await fetch('https://file-up.afo.im/list');
替换https://file-up.afo.im/list为你的

创建 Pages,连接 Git 存储库#

  1. 不教了,简单的雅痞。可见教你搭建你的第一个网站!无需服务器即可上手!注意要用 Git 存储库部署而不是本地部署

  2. Cloudflare Pages 当有提交时会自动重新部署,实现新文件自动更新

访问#

image

  • 写的仓促,有问题评论问
加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。