workersKV免费创建无限空间小文件云储存

因为R2要绑定信用卡,不适合多账号无线创建,因此,本文教你一键将cfworker(KV)变成小文件云储存器
目标计划:
分片储存大文件
注意:CF规则里好像有禁止储存流媒体,为避免封号,不要存视频,大图等想作死小图还是可以的
注意,只能储存小文件,太大会报413错误!
第一步:创建worker
第二步,绑定KV_FILE到worker
第三部,根据实际情况写入以下代码:

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

const ACCESS_CODE = "workerkvfile";
const KV_NAMESPACE = KV_FILE;

async function handleRequest(request) {
  const url = new URL(request.url);
  const path = url.pathname.split("/")[1];
  const accesscode = url.searchParams.get("accesscode");

  if (accesscode !== ACCESS_CODE) {
    return new Response("Invalid access code.", { status: 403 });
  }

  switch (path) {
    case "upload":
      return uploadFile(request);
    case "fetch":
      const id = url.searchParams.get("id");
      return fetchFile(id);
    case "delete":
      const deleteId = url.searchParams.get("id");
      return deleteFile(deleteId);
    default:
      return new Response("Invalid request.", { status: 400 });
  }
}

async function uploadFile(request) {
  // 检查Content-Type是否为multipart/form-data
  const contentType = request.headers.get("content-type") || "";
  if (!contentType.includes("multipart/form-data")) {
      return new Response("Unsupported file type.", { status: 400 });
  }

  // 使用FormData解析文件数据
  const formData = await request.formData();
  const file = formData.get("file");
  if (!file) {
      return new Response("File not found in request.", { status: 400 });
  }

  // 转换为二进制数据
  const arrayBuffer = await file.arrayBuffer();
  const id = crypto.randomUUID();

  // 存储文件
  await KV_NAMESPACE.put(id, arrayBuffer, { metadata: { contentType: file.type } });

  return new Response(id, {
      status: 200,
      headers: {
          "Content-Type": "text/plain",
      },
  });
}

async function fetchFile(id) {
  const fileData = await KV_NAMESPACE.getWithMetadata(id, "arrayBuffer");
  if (!fileData.value) {
    return new Response("File not found.", { status: 404 });
  }

  // 直接以二进制形式返回文件数据和正确的Content-Type
  return new Response(fileData.value, {
    status: 200,
    headers: {
      "Content-Type": fileData.metadata.contentType || "application/octet-stream",
    },
  });
}

async function deleteFile(id) {
  await KV_NAMESPACE.delete(id);
  return new Response("File deleted successfully.", { status: 200 });
}

accececode可修改
无限空间教程:
先搞个无限邮箱:
https://zhile.io/2023/12/09/pandoranext-introduction.html
无限注册账号,每个账号有IGB,不够用的时候就加。
附:调用示例:
python

import requests

# Worker的基础URL
BASE_URL = "你的部署URL"
# 预设的访问码
ACCESS_CODE = "workerkvfile"

def upload_file(file_path):
    """上传文件到Worker"""
    files = {'file': open(file_path, 'rb')}
    response = requests.post(f"{BASE_URL}/upload?accesscode={ACCESS_CODE}", files=files)
    if response.status_code == 200:
        return response.text
    else:
        print("上传失败:", response.text)
        return None

def fetch_file(file_id, save_path):
    """从Worker下载文件"""
    response = requests.get(f"{BASE_URL}/fetch?id={file_id}&accesscode={ACCESS_CODE}")
    if response.status_code == 200:
        with open(save_path, 'wb') as f:
            f.write(response.content)
        print("文件下载成功")
    else:
        print("下载失败:", response.text)

def delete_file(file_id):
    """从Worker删除文件"""
    response = requests.get(f"{BASE_URL}/delete?id={file_id}&accesscode={ACCESS_CODE}")
    if response.status_code == 200:
        print("文件删除成功")
    else:
        print("删除失败:", response.text)

if __name__ == "__main__":
    # 文件路径
    file_path = "test.jpg"
    save_path = "downloaded_test.jpg"

    # 上传文件
    print("正在上传文件...")
    file_id = upload_file(file_path)
    if file_id:
        print(f"文件上传成功,ID: {file_id}")

        # 下载文件
        print("正在下载文件...")
        fetch_file(file_id, save_path)

        # 删除文件
        print("正在删除文件...")
        delete_file(file_id)

8 Likes

先mark一下

常规话题软件开发

大善人被薅秃了

‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌

‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌‌

大善人让你薅成秃头了,完犊子

同mark一下

用 cf 薅 cf

是个很人。。

1 Like