文章摘要
加载中...|
此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结 投诉

Alist使用Cloudflare Worker代理下载云盘文件

重要提示

在开始之前,请注意以下风险:

  • Cloudflare 的ToS中禁止了这类代理加速的用途,可能会导致你CF账号封禁
  • 可能会导致你的云盘账号风控甚至封禁
  • AlistGo/alist-proxy 此仓库已经长时间未更新,未来可能不再适配
  • OpenList 目前大概率可以使用

为什么要使用CF Worker代理下载?

1. 节省VPS资源

对于部分只能本机代理的云盘,代理下载走的是CF。所以如果你VPS带宽很小或者流量很少/流量很贵,走代理地址下载就可以不走你的VPS了。

来自alistgo.com来自alistgo.com

2. 解决跨网限速

对于天翼云盘跨网QoS可能是一个解决办法。

引用站外地址,请注意甄别链接安全性

其他用法

其他用法同样可以补充,欢迎在评论区分享你的使用经验。

使用要求

使用CF Worker加速需要满足以下条件:

  • ✅ Cloudflare 账号
  • ✅ 暴露在公网的Alist
  • ✅ 最好还需要一个托管在CF账号的域名(Worker提供的域名被墙了)

一、Cloudflare部分

1. 创建Worker项目

点击创建项目:

WorkerWorker

点击开始使用:

WorkerWorker

填写项目名:

WorkerWorker

2. 编辑代码

编辑代码:

WorkerWorker

复制代码到CF的编辑器中,你也可以直接点击这里下载代码

代码来源

该代码来自 AlistGo/alist-proxy

点击查看完整代码
// src/const.ts
var ADDRESS = "YOUR_ADDRESS";
var TOKEN = "YOUR_TOKEN";
var WORKER_ADDRESS = "YOUR_WORKER_ADDRESS";

// src/verify.ts
var verify = async (data, _sign) => {
  const signSlice = _sign.split(":");
  if (!signSlice[signSlice.length - 1]) {
    return "expire missing";
  }
  const expire = parseInt(signSlice[signSlice.length - 1]);
  if (isNaN(expire)) {
    return "expire invalid";
  }
  if (expire < Date.now() / 1e3 && expire > 0) {
    return "expire expired";
  }
  const right = await hmacSha256Sign(data, expire);
  if (_sign !== right) {
    return "sign mismatch";
  }
  return "";
};
var hmacSha256Sign = async (data, expire) => {
  const key = await crypto.subtle.importKey(
    "raw",
    new TextEncoder().encode(TOKEN),
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["sign", "verify"]
  );
  const buf = await crypto.subtle.sign(
    {
      name: "HMAC",
      hash: "SHA-256"
    },
    key,
    new TextEncoder().encode(`${data}:${expire}`)
  );
  return btoa(String.fromCharCode(...new Uint8Array(buf))).replace(/\+/g, "-").replace(/\//g, "_") + ":" + expire;
};

// src/handleDownload.ts
async function handleDownload(request) {
  const origin = request.headers.get("origin") ?? "*";
  const url = new URL(request.url);
  const path = decodeURIComponent(url.pathname);
  const sign = url.searchParams.get("sign") ?? "";
  const verifyResult = await verify(path, sign);
  if (verifyResult !== "") {
    const resp2 = new Response(
      JSON.stringify({
        code: 401,
        message: verifyResult
      }),
      {
        headers: {
          "content-type": "application/json;charset=UTF-8"
        }
      }
    );
    resp2.headers.set("Access-Control-Allow-Origin", origin);
    return resp2;
  }
  let resp = await fetch(`${ADDRESS}/api/fs/link`, {
    method: "POST",
    headers: {
      "content-type": "application/json;charset=UTF-8",
      Authorization: TOKEN
    },
    body: JSON.stringify({
      path
    })
  });
  let res = await resp.json();
  if (res.code !== 200) {
    return new Response(JSON.stringify(res));
  }
  request = new Request(res.data.url, request);
  if (res.data.header) {
    for (const k in res.data.header) {
      for (const v of res.data.header[k]) {
        request.headers.set(k, v);
      }
    }
  }
  let response = await fetch(request);
  while (response.status >= 300 && response.status < 400) {
    const location = response.headers.get("Location");
    if (location) {
      if (location.startsWith(`${WORKER_ADDRESS}/`)) {
        request = new Request(location, request);
        return await handleRequest(request);
      } else {
        request = new Request(location, request);
        response = await fetch(request);
      }
    } else {
      break;
    }
  }
  response = new Response(response.body, response);
  response.headers.delete("set-cookie");
  response.headers.set("Access-Control-Allow-Origin", origin);
  response.headers.append("Vary", "Origin");
  return response;
}

// src/handleOptions.ts
function handleOptions(request) {
  const corsHeaders = {
    "Access-Control-Allow-Origin": "*",
    "Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS",
    "Access-Control-Max-Age": "86400"
  };
  let headers = request.headers;
  if (headers.get("Origin") !== null && headers.get("Access-Control-Request-Method") !== null) {
    let respHeaders = {
      ...corsHeaders,
      "Access-Control-Allow-Headers": request.headers.get("Access-Control-Request-Headers") || ""
    };
    return new Response(null, {
      headers: respHeaders
    });
  } else {
    return new Response(null, {
      headers: {
        Allow: "GET, HEAD, POST, OPTIONS"
      }
    });
  }
}

// src/handleRequest.ts
async function handleRequest(request) {
  if (request.method === "OPTIONS") {
    return handleOptions(request);
  }
  return await handleDownload(request);
}

// src/index.ts
var src_default = {
  async fetch(request, env, ctx) {
    return await handleRequest(request);
  }
};
export {
  src_default as default
};
//# sourceMappingURL=index.js.map

3. 配置参数

代码中有三个值需要我们填写,分别是 ADDRESSTOKENWORKER_ADDRESS

WorkerWorker

参数说明

  • ADDRESS: 你部署的Alist的下载地址
  • WORKER_ADDRESS: 你创建的Worker地址(如果你稍后要绑定域名,填写你需要绑定的域名)
  • TOKEN: Alist的Token,可以在Alist的设置里面找到

获取Alist Token

在Alist的设置页面可以找到Token:

Alist-settings-otherAlist-settings-other

填写配置

按照如下图填写参数:

WorkerWorker

点击右上角部署完成之后,就可以关掉Cloudflare的网页了。

二、Alist部分

配置存储

以天翼云盘为例,填写完其他部分后,把WebDAV策略改成使用代理地址,并把你的Worker地址填写在下载代理URL中:

Alist-storages-editAlist-storages-edit

Web代理说明

Web代理可以根据自己需要勾选,一般情况下不用。详见相关文档

点击保存之后,流量就是走Cloudflare了。

其他代理方式

当然,你也可以自己使用服务器代理流量,相关文档请参考: 下载代理URL文档

测试地址

这是一个非常简单的教程。为了验证天翼云盘代理下载是否能解决跨网限速问题,我提供一个测试地址:

测试说明

同时也测试一下会不会风控。挂载的天翼云盘账号没有会员,2T空间。

代码原理解析

整体架构

这个Cloudflare Worker代码实现了一个安全的代理下载服务,主要包含以下几个核心模块:

模块说明

  • 配置模块 (const.ts): 存储Alist地址、Token和Worker地址
  • 验证模块 (verify.ts): 实现HMAC-SHA256签名验证
  • 下载处理模块 (handleDownload.ts): 处理代理下载逻辑
  • CORS处理模块 (handleOptions.ts): 处理跨域请求
  • 主入口模块 (index.ts): Worker的主要入口点

核心工作流程

1. 请求验证机制

javascript
const verifyResult = await verify(path, sign);

Worker首先会验证请求的合法性:

签名验证原理
  1. 提取签名信息: 从URL参数中获取sign参数
  2. 解析过期时间: 签名格式为signature:timestamp,提取时间戳
  3. 检查是否过期: 比较当前时间与签名中的时间戳
  4. 重新计算签名: 使用相同的算法和密钥重新计算签名
  5. 对比验证: 比较计算出的签名与传入的签名是否一致

2. Alist API调用

javascript
let resp = await fetch(`${ADDRESS}/api/fs/link`, {
  method: "POST",
  headers: {
    "content-type": "application/json;charset=UTF-8",
    Authorization: TOKEN
  },
  body: JSON.stringify({ path })
});

验证通过后,Worker会:

  • 调用Alist的/api/fs/link接口获取真实下载链接
  • 使用配置的TOKEN进行身份验证
  • 传递文件路径参数

3. 代理下载处理

javascript
request = new Request(res.data.url, request);
let response = await fetch(request);

获取到真实下载链接后:

javascript
while (response.status >= 300 && response.status < 400) {
  const location = response.headers.get("Location");
  if (location.startsWith(`${WORKER_ADDRESS}/`)) {
    // 如果重定向到Worker自身,递归处理
    return await handleRequest(request);
  } else {
    // 否则跟随重定向
    request = new Request(location, request);
    response = await fetch(request);
  }
}

安全机制分析

HMAC-SHA256签名算法

javascript
const key = await crypto.subtle.importKey(
  "raw",
  new TextEncoder().encode(TOKEN),
  { name: "HMAC", hash: "SHA-256" },
  false,
  ["sign", "verify"]
);
赞赏博主
评论 隐私政策