前言

总所周知OneDrive在国内的直连下载速度有待提高。就我而言,由于我个人是做一站式ROM资源站的,由AlistV3搭建起来资源站并挂载OneDrive网盘(因为国内网盘内存小,大内存需要收费),对下载速度也有一定要求,毕竟一个ROM从1G到4G不等,前几天在Cloudflare和AlistV2文档里找到了可以通过Cloudflare Workers路由实现中转的教程,但是存在一些问题,所以写下这篇,供大家参考。

教程

前提条件

首先你需要一个Cloudflare账号和一个挂载好OneDrive的AlistV3网盘。Cloudflare和AlistV3的官方文档如下,可以参考如何安装和挂载:
Cloudflare注册网址:点击访问
AlistV3文档地址:点击访问

获取AlistV3的token

从这一步开始,就和Alist V2的官方文档就对不上了,和众多教程里获取Alist的token方式也不一样,AlistV3所谓的token不是官方所提供的方法里的,而是放在了后台管理里面的设置-其他选项卡里面

点击上面的复制令牌,该令牌就是我们所需要的“token”

搭建Cloudflare Workers

登录Cloudflare

在左侧选择Workers选项卡

创建服务器

服务器名称可以自定义

填入Workers代码

点击快速编辑,并填入Workers代码

Workers代码如下,如果GitHub上有新版本更新,请使用最新的版本部署。

"YOUR_ADDRESS"引号里面改成你自己的AlistV3地址,必须添加协议头且最后面不能加/。如:https://pan.winboard.top
"YOUR_TOKEN"冒号里面填写AlistV3里面提供的令牌

代码:

// src/const.ts
var ADDRESS = "YOUR_ADDRESS";
var TOKEN = "YOUR_TOKEN";

// 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);
  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/index.ts
var src_default = {
  async fetch(request, env, ctx) {
    if (request.method === "OPTIONS") {
      return handleOptions(request);
    }
    return handleDownload(request);
  }
};
export {
  src_default as default
};
//# sourceMappingURL=index.js.map

添加自定义域

由于Cloudflare所提供的域名可能被墙,建议使用自定义域,但是大多数教程所提供的手动添加自定义域的方式在2022-11月时已经失效,只能在主面板中的Workers里面添加。同时也要注意,添加自定义域名的时候不要使用任何代理,因为Cloudflare已经于去年11月不再允许CNAME解析也不再允许Workers用户手动指定IP,而是Cloudflare自动指派所在地区最佳IP,网上很多教程写过的优选IP教程受到规则影响已经无法使用。

等待DNS解析成功后进行下一步

添加路由

点击同页面下面的添加路由按钮,输入刚刚的自定义域名并加上/*

设置AlistV3

在AlistV3的储存选项里,选择一个OneDrive储存器,在“下载代理URL”里填入刚刚的自定义域并开启“Web代理”选项,然后点击保存即可

接下来下载文件,就应该通过Workers路由了~

写在最后

1.下载代理中转只会在你挂载的路径下生效;
2.这种方法理论上可以适用于其他网盘,但也许没必要,用在其他网盘上也有可能有被封号的风险;
3.Openlist和Alist网盘的原理类似,此方法经测试可行;
4.体验进入网盘下载文件即可!

发表评论