0%

临时解决方案:Cloudflare Workers与镜像站

最早接触到Cloudflare是在研究jsdelivr被墙后的解决方案,发现一个cloudflare.jsdelivr.net的节点。那是我第一次听到Cloudflare的大名。可没想到,真正把我拉回Cloudflare的,不是所谓高防DDOS,也不是CDN加速,竟梅开二度又是被墙。这次,是Cloudflare自己被墙了。

引用另一篇文章(Hexo网站教程):

《论我捣鼓GiTalk的简要过程》

写到这里我本想去截图,结果一看启动不起来,没办法新建issue也没法登录GitHub账号。在排查了设置、网络的问题后,我发现有个致命的问题:cors-anywhere.azm.workers.dev被墙掉,然后GiTalk无法进行GitHub oauth,就不能用了。

我于是尝试自己搭worker,结果发现是所有Cloudflare worker的链接都被墙掉了,然后我就彻底没招了,就只好作罢。不过……真的吗?

后来我找到了GiTalk的仓库,里面有类似的Issue,甚至翻出了CORS Anywhere的仓库,找到了一个基于Heroku的备用demo链接。在一个Issue某条评论某条评论中找到了一些备用链接。于是,就可以恢复正常了!

另及:今年(2022)11月28号Heroku会关闭所有的免费服务,所以你看到类似herokuapp.com的链接都不用试了…

这个cors-anywhere.azm.workers.dev,就是基于Cloudflare Workers的。上文也提到了我自己搭Workers,在这其中也有一点意外地收获。

1. 关于我们今天到底在干什么

Cloudflare Workers,乍一听,我也没猜出这是什么东西。其实WorkersCloudflare提供的免费服务器,类似GitHub给你一个二级域名(GitHub就是github.ioCloudflare Workersworkers.dev)。这个CF Workers是支持自定义处理逻辑,说白点自己用JavaScript写脚本。当然我不会把事情变得太复杂,肯定是有可重用的模板的。

但是我们没事儿搭服务器干嘛?不知道各位有没有听说过反向代理这回事。差不多如此:

1
2
3
4
5
6
7
Client --> BlockedServer: GET xxx
note left of Client: I cannot GET!
Client -> CF Worker: GET Blocked Server for me!
note right of CF Worker: I can GET!
CF Worker -> BlockedServer: GET xxx
BlockedServer -> CF Worker: Responce xxx
CF Worker -> Client: Responce xxx

其实说白了这也是一种fq的方式嘛。

2. 关于你的Cloudflare账号

照例的话,我们肯定是要简要说一下官网和账号的….https://www.cloudflare.com/,很人性化的就跳到中文版啊。

然后点击注册就好了耶:

然后有一些配置,按照自己的喜好填就好了啊。不过由于资金问题和一些使用方式上的原因,我们选Free Plan就可以了,千万不要为了这个白买高级版,每天100000个请求完全完全够用了!

3. 开始搭建Worker

3.1 初始化Worker

我们接下来以访问速度慢的GitHub和无法访问的Google为例。

我们在左侧的菜单中找到Workers,然后新建服务:

由于我们只需要一个worker就可以完成一切任务,我就没有新注册了。

进来之后有这样一个界面:

我们点击快速编辑,进入编辑页面:

左边是处理逻辑,右边则是预览部分。

3.2 加入代码

先复制一下下面这段代码:

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// 你要镜像的网站.
const upstream = 'www.google.com'

// 镜像网站的目录,比如你想镜像某个网站的二级目录则填写二级目录的目录名,镜像 google 用不到,默认即可.
const upstream_path = '/'

// 镜像站是否有手机访问专用网址,没有则填一样的.
const upstream_mobile = 'www.google.com'

// 屏蔽国家和地区.
const blocked_region = ['KP', 'SY', 'PK', 'CU']

// 屏蔽 IP 地址.
const blocked_ip_address = ['0.0.0.0', '127.0.0.1']

// 镜像站是否开启 HTTPS.
const https = true

// 文本替换.
const replace_dict = {
'$upstream': '$custom_domain',
'//www.google.com': ''
}

// 以下保持默认,不要动
addEventListener('fetch', event => {
event.respondWith(fetchAndApply(event.request));
})

async function fetchAndApply(request) {

const region = request.headers.get('cf-ipcountry').toUpperCase();
const ip_address = request.headers.get('cf-connecting-ip');
const user_agent = request.headers.get('user-agent');

let response = null;
let url = new URL(request.url);
let url_hostname = url.hostname;

if (https == true) {
url.protocol = 'https:';
} else {
url.protocol = 'http:';
}

if (await device_status(user_agent)) {
var upstream_domain = upstream;
} else {
var upstream_domain = upstream_mobile;
}

url.host = upstream_domain;
if (url.pathname == '/') {
url.pathname = upstream_path;
} else {
url.pathname = upstream_path + url.pathname;
}

if (blocked_region.includes(region)) {
response = new Response('Access denied: WorkersProxy is not available in your region yet.', {
status: 403
});
} else if (blocked_ip_address.includes(ip_address)) {
response = new Response('Access denied: Your IP address is blocked by WorkersProxy.', {
status: 403
});
} else {
let method = request.method;
let request_headers = request.headers;
let new_request_headers = new Headers(request_headers);

new_request_headers.set('Host', url.hostname);
new_request_headers.set('Referer', url.hostname);

let original_response = await fetch(url.href, {
method: method,
headers: new_request_headers
})

let original_response_clone = original_response.clone();
let original_text = null;
let response_headers = original_response.headers;
let new_response_headers = new Headers(response_headers);
let status = original_response.status;

new_response_headers.set('access-control-allow-origin', '*');
new_response_headers.set('access-control-allow-credentials', true);
new_response_headers.delete('content-security-policy');
new_response_headers.delete('content-security-policy-report-only');
new_response_headers.delete('clear-site-data');

const content_type = new_response_headers.get('content-type');
if (content_type.includes('text/html') && content_type.includes('UTF-8')) {
original_text = await replace_response_text(original_response_clone, upstream_domain, url_hostname);
} else {
original_text = original_response_clone.body
}

response = new Response(original_text, {
status,
headers: new_response_headers
})
}
return response;
}

async function replace_response_text(response, upstream_domain, host_name) {
let text = await response.text()

var i, j;
for (i in replace_dict) {
j = replace_dict[i]
if (i == '$upstream') {
i = upstream_domain
} else if (i == '$custom_domain') {
i = host_name
}

if (j == '$upstream') {
j = upstream_domain
} else if (j == '$custom_domain') {
j = host_name
}

let re = new RegExp(i, 'g')
text = text.replace(re, j);
}
return text;
}


async function device_status(user_agent_info) {
var agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
var flag = true;
for (var v = 0; v < agents.length; v++) {
if (user_agent_info.indexOf(agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

然后我们把它复制到左边的代码块中。这里面有几个我们需要修改的地方:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 你要镜像的网站.
const upstream = 'www.google.com'

// 镜像网站的目录,比如你想镜像某个网站的二级目录则填写二级目录的目录名,镜像 google 用不到,默认即可.
const upstream_path = '/'

// 镜像站是否有手机访问专用网址,没有则填一样的.
const upstream_mobile = 'www.google.com'

// 文本替换.
const replace_dict = {
'$upstream': '$custom_domain',
'//www.google.com': ''
}

一定要保证upstreamupstream_mobilereplace_dict中三个网址是一样的。

然后保存一下,点保存并部署即可。

现在看一下效果吧:

可惜的是,那个部署出来的workers.dev链接是不能使用的。不过反过来想,我们已经获得了谷歌的永久访问,不是么?

THE END感谢您的阅读~

赏作者一杯作业......