前言

自從 jsDelivr 被 DNS 污染後,比較常用的解決方法是使用其鏡像代替,例如 fastly.jsdelivr.netgcore.jsdelivr.netcf.jsdelivr.net,但是這些鏡像不能保證將來是否能保持活躍。所以,使用反向代理是最有效的一個解決方案。

這裡使用了 Cloudflare Workers 進行反向代理,Cloudflare Workers 提供每天 10 萬次的請求數量,搭配 CDN 又可以通過緩存大大減少請求數。同時也可以設置防盜鏈和加密 URL 以防止濫用。

參考:https://www.430074.xyz/posts/workers-jsdeliver.html

快速上手

創建 Workers

打開 Cloudflare 儀錶板,轉到 Workers,創建一個新項目

編輯代碼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
// 允许的 CORS 来源
const ALLOWED_REFERER = [
/^https?:\/\/localhost(:\d*)?\/.*$/,
/^https?:\/\/([\w-]+\.)*w3schools\.com(:\d*)?\/.*$/
];
// 是否允许所有无 Referer 请求
const ALLOW_NO_ORIGIN = true;
//输入你的密码,密码加在path后面做SHA-1运算
const MYSECRET = "123456";


function validateReferer(req) {
const referer = req.headers.get('Referer');
if (referer) {
for (const el of ALLOWED_REFERER) {
if (el.exec(referer)) {
return true;
}
}
return false;
}
return ALLOW_NO_ORIGIN; // 是否拒绝所有无 Referer 请求
}


async function handle(request) {
let url = new URL(request.url);
const acceptType = request.headers.get('Accept');
const hash_request = url.pathname.split("/")[1];
const path_real = url.pathname.substring(hash_request.length + 1, url.pathname.length);
url.hostname = "cdn.jsdelivr.net";
url.pathname = path_real;

if (!(await validatePath(hash_request, path_real))) {
return new Response('Error Hash', {
status: 403
});
}

if (!(validateReferer(request))) {
return new Response('Blocked Host', {
status: 403
});
}

return await fetch(url);
}

async function validatePath(hash_request, path_real) {
const message = new TextEncoder().encode(path_real + MYSECRET);
const myDigest = await crypto.subtle.digest('SHA-1', message);
const hashArray = Array.from(new Uint8Array(myDigest));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return (hashHex == hash_request);
}


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

編輯下面參數

  1. 修改 ALLOWED_REFERER 常量,裡麵包含了可以使用本服務的域名列表。按照模板,修改成自己的域名,需要使用正則表達式。同時 ALLOW_NO_ORIGIN = true 是表示允許無 Referer 訪問本服務,比如直接瀏覽器打開。
  2. 修改密碼 MYSECRET,這裡的密碼是用來加密 URL 的,因為 Referer 可以偽造,所以為了避免他人濫用,所以需要密碼進行加密。

正斜杠 / 前需要加上反斜杠 \ 用於轉義

如果對正則表達式不熟悉,可以使用 Regex Vis (一個正則表達式可視化工具),右上角可以切換語言。

如果不需要防盜鏈和加密,可以注釋掉下面內容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-  if (!(await validatePath(hash_request, path_real))) {
- return new Response('Error Hash', {
- status: 403
- });
- }
-
- if (!(validateReferer(request))) {
- return new Response('Blocked Host', {
- status: 403
- });
- }
+ // if (!(await validatePath(hash_request, path_real))) {
+ // return new Response('Error Hash', {
+ // status: 403
+ // });
+ // }
+
+ // if (!(validateReferer(request))) {
+ // return new Response('Blocked Host', {
+ // status: 403
+ // });
+ // }

綁定域名

進入一個域,轉到 DNS,添加一條 A 記錄,IP 值隨意,打開右邊的 CDN

轉到 Workers,為二級域名設置路由,選中剛剛部署的 Workers 服務

如果你想使用未通過 NS 接入 Cloudflare 的域名設置路由,也可以使用 SaaS 通過 IP/CNAME 接入,fallback.b.com 作為回退源,任意指向一個 IP,將 demo.a.com 指向 fallback.b.com,然後在 b.com 的域下為 demo.a.com/* 設置路由。

參考:

添加 WAF 規則(可選)

添加一條 WAF 規則作為防盜鏈,腳本中的防盜鏈就可以注釋掉

轉到 Security 中的 WAF,創建一條規則

該規則釋義為如果 Referer 不包含 example.com,且請求的主機名中等於 raw.example.com,則阻斷

獲得加密請求 URL

  1. 假設 Workers 綁定的域名是 w3schools.com ,密碼是 123456 ,想要反代的是 /npm/[email protected]/dist/jquery.min.js
  2. 獲得帶加密的明文,為 url.path + 密碼,如上則是 /npm/[email protected]/dist/jquery.min.js123456 。獲得該字符串的 SHA-1 編碼 。得到密文 371388c8eafe02c8876f67abe1d170b920218881
  3. 生成新的請求 URL :域名 + /密文 + 原 url.path。如上文則是 https://w3schools.com/371388c8eafe02c8876f67abe1d170b920218881/npm/[email protected]/dist/jquery.min.js