更新
劝退三一连 首先你要有个 Cloudflare 账户,这是必须的。关于 Cloudflare 的注册咱就不多说啦,不过咱倒是建议大家伙把域名的 DNS 解析放到 Cloudflare 上来,好处多多:有把 https 小绿锁、免费的 加速 减速 CDN (墙内)、域名访问统计等等可玩性比较高😋。需要注意的是 Cloudflare 的 Worker 一天 10 万次免费额度,也够咱喝一壶的啦,不用担心不够用。
新建 Worker 登录到 Cloudflare 的大盘面板,点击左上角的 Menu
—-> Workers
进入到 Workers 页面。新注册的用户会提示设置一个 workers.dev
顶级域名下的二级子域名,这个子域名设置好之后是不可更改的,之后你新创建的 Worker 就会使以这个域名而二级子域名开始的,类似于 WorkerName.yousetdomain.workers.dev
。yousetdomain
就是你要设置的二级子域名,WorkerName
可以自定义,默认是随机生成的。也可以给自己的域名添加一条 CNAME 到 WorkerName.yousetdomain.workers.dev
,这样使用自己的域名就可以访问到 Worker
了。
设置好二级子域名之后选择 free 套餐计划,然后进入到 Worker 管理界面,创建一个新的 Worker
然后在 Script
输入框里填入以下代码。俗话说代码写得好,同行抄到老 ,咱的 worker.js
代码是参考自 Workers-Proxy ,不过咱去掉了一些无关紧要的代码,原代码是加入了辨别移动设备适配域名、屏蔽某些 IP 和国家的功能。对于咱的 telegram 频道镜像站来说,这都是多余的,于是就去掉了。
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 // Website you intended to retrieve for users. const upstream_me = 't.me'; const upstream_org = 'telegram.org'; // Custom pathname for the upstream website. const upstream_path = '/s/rss_kubernetes'; // Whether to use HTTPS protocol for upstream address. const https = true; // Replace texts. const replace_dict = { $upstream: '$custom_domain' }; addEventListener('fetch', event => { event.respondWith(fetchAndApply(event.request)); }); async function fetchAndApply(request) { let response = null; let url = new URL(request.url); let url_hostname = url.hostname; if (https == true) { url.protocol = 'https:'; } else { url.protocol = 'http:'; } var upstream_domain = upstream_me; // Check telegram.org let pathname = url.pathname; console.log(pathname); if (pathname.startsWith('/static')) { console.log('here'); upstream_domain = upstream_org; url.pathname = pathname.replace('/static', ''); } else { if (pathname == '/') { url.pathname = upstream_path; } else { url.pathname = upstream_path + url.pathname; } } url.host = upstream_domain; 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 response_headers = original_response.headers; let status = original_response.status; response = new Response(original_response.body, { status, headers: response_headers }); let text = await response.text(); // Modify it. let modified = text.replace( /telegram.org/g, 'tg.k8s.li/static' ); // Return modified response. return new Response(modified, { status: response.status, statusText: response.statusText, headers: response.headers }); }
需要注意的是,像 t.me
域名下的站点,比如我的 https://t.me/s/rss_kubernetes
,它的 js 和 css 样式文件是使用的 telegram.org 域名。所以我们需要在 replace_dict
那里定义好替换的正则表达式,将 https://t.me/s/rss_kubernetes
页面里的 telegram.org
同样进行反代才行,这需要为 telegram 建一个单独的 Worker 😑。这也是评论区 ChrAlpha 小伙伴提到的办法。
1 2 3 4 5 6 7 8 ubuntu@blog:~$ curl https://t.me/s/rss_kubernetes | grep "<script src=" % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 141k 100 141k 0 0 85287 0 0:00:01 0:00:01 --:--:-- 85237 <script src="//telegram.org/js/jquery.min.js"></script> <script src="//telegram.org/js/jquery-ui.min.js"></script> <script src="//telegram.org/js/widget-frame.js?29"></script> <script src="//telegram.org/js/telegram-web.js?8"></script>
修改下处代码为,将https://t.me/s/rss_kubernetes
页面里的 telegram.org
同样进行一次反代。这样访问到 https://t.me/s/rss_kubernetes
页面时,把的 telegram.org 替换为另一个 Worker 的域名,比如我的 telegram.k8srss.workers.dev
。不过像频道里的图片、文件、视频等资源 telegram 是使用的 CDN ,而且有好几个域名……这点很僵硬,暂时找不到合适的办法。貌似一个 Worker 只能反代一个域名?如果汝有合适的办法,欢迎与咱交流,咱感激不尽😋
1 let modified = text.replace(/telegram.org/g, "telegram.k8srss.workers.dev")
这样再使用 curl 访问测试一下,原来的 telegram.org 已经全部替换成 telegram.k8srss.workers.dev 了😂。现在墙内用户也可以无痛访问啦。在此感谢 ChrAlpha 小伙伴😂提出宝贵的建议。
1 2 3 4 5 6 7 8 </main> <script src="//telegram.k8srss.workers.dev/js/jquery.min.js"></script> <script src="//telegram.k8srss.workers.dev/js/jquery-ui.min.js"></script> <script src="//telegram.k8srss.workers.dev/js/widget-frame.js?29"></script> <script src="//telegram.k8srss.workers.dev/js/telegram-web.js?8"></script> <!-- page generated in 121.26ms -->
这个文本替换功能很好玩儿,在 Cloudflare 官方的博客里还有个 demo introducing-cloudflare-workers 。使用这个功能咱有解锁了一个玩具,稍后再讲😂。
Here is a worker which performs a site-wide search-and-replace, replacing the word “Worker” with “Minion”. Try it out on this blog post.
剽窃修改好代码之后点击左下角的 Save and Deploy
然后 Preview 看看页面是否显示正常,如果显示正常恭喜你成功啦。
如果你想使用这种办法反代其他频道,只需要把 const upstream_path = '/s/rss_kubernetes'
后的 rss_kubernetes 替换为你想要代理的 telegram 频道 username 即可。之所以加上 upstream_path
而不反代整个 t.me
是为了防止别人滥用,毕竟 10W 次不经薅😂
改进 周四晚上睡觉前在推特上发了个推文,向大家请教了一下之前一个 Worker 里只能反代一个域名的问题。第二天 @Echowxsy 就回复咱了,而且还特意注册了 CouldFare 账号使用 Workers 帮咱测试了一下。在此非常感谢 @Echowxsy 帮咱。按照 @Echowxsy 小伙伴所说的:
我没用过 CloudFlare,不过我看了一下你的blog,貌似可以用两个upstream实现这个功能。 在modified那里替换为当前worker的地址,然后在后面加上一个不会重复的路径,例如xxx。 然后在fetchAndApply里面判断,如果当前请求的pathname=/xxx,使用upstream2,否则使用upstream1。 理论上是可以实现的。
就是一个 Workers 可以做很多事情,他实际上就是 Node.js 代码。 然后这里是将 http://telegram.org/xxxx 映射到 http://tg.k8s.li/static/xxxx 。 然后在 Workers 里面判断,如果有 /static
则从 http://telegram.org 获取,否则从 http://t.me 获取。
此处引用
@Echowxsy 的 推文
Woerker 首先我们获取完要反代的 https://t.me/s/rss_kubernetes
页面 html 源码,然后使用 replace 函数把 telegram.org 以及cdn[1-5].telesco.pe 等域名进行替换,替换为 /static 、/cdn[1-5] 等不同的 url 路径。然后将修改后的 html 页面返回给客户端。客户端客户端在请求 /static
时 Worker 就会去 http://telegram.org 获取相应的资源返回给用户。这样就实现了一个 Worker 反代多个域名骚操作。修改后的代码如下:
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 const upstream_me = 't.me'; const upstream_org = 'telegram.org'; // Custom pathname for the upstream website. const upstream_path = '/s/rss_kubernetes'; // Whether to use HTTPS protocol for upstream address. const https = true; // Replace texts. const replace_dict = { $upstream: '$custom_domain' }; addEventListener('fetch', event => { event.respondWith(fetchAndApply(event.request)); }); async function fetchAndApply(request) { let response = null; let url = new URL(request.url); let url_hostname = url.hostname; if (https == true) { url.protocol = 'https:'; } else { url.protocol = 'http:'; } var upstream_domain = upstream_me; // Check telegram.org let pathname = url.pathname; console.log(pathname); if (pathname.startsWith('/static')) { console.log('here'); upstream_domain = upstream_org; url.pathname = pathname.replace('/static', ''); } else { if (pathname == '/') { url.pathname = upstream_path; } else { url.pathname = upstream_path + url.pathname; } } url.host = upstream_domain; 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 response_headers = original_response.headers; let new_response_headers = new Headers(response_headers); let status = original_response.status; response = new Response(original_response_clone.body, { status, headers: new_response_headers }); let text = await response.text(); // Modify it. let modified = text.replace(/telegram.org/g,'tg.k8s.li/static'); // Return modified response. return new Response(modified, { status: response.status, statusText: response.statusText, headers: response.headers }); }
自定义域名 回到 Workers 的管理页面,点击 rename
即可修改 Worker 的三级子域名。不过咱还是不太喜欢 WorkerName.yousetdomain.workers.dev
这么长的域名,想使用咱自己的二级子域名访问。
首先回到域名管理的页面,进入到自己域名顶部那一栏里的 Workers
,在那里添加相应的路由即可。
点击 Add Route
,在 Route 那一栏输入好自己的域名,注意最后的 /*
也要加上,然后 Worker 选择刚刚创建的那个即可。接着再添加 CNAME
记录到自己的 WorkerName.yousetdomain.workers.dev
,这样就能使用自己的域名访问啦😋
文本替换 前文提到的文本替换功能帮咱解决了一个小问题。咱友链关注的一个博客 chanshiyu.com 没有提供 RSS ,他是将博客内容放在 GitHub issue 上,所以只能通过 RSSHUB 来订阅 GitHub 的 issue 来获取博客的更新。但 RSSHUB 获取的是 GitHub issue 的链接而非原博客的链接,于是咱想了想就用 Worker
进行替换不得了。
通过 RSSHUB 获取到的 RSS 数据如下:
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 <rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> <channel> <title> <![CDATA[ chanshiyucx/blog Issues ]]> </title> <link>https://github.com/chanshiyucx/blog/issues</link> <atom:link href="http://rsshub.app/github/issue/chanshiyucx/blog" rel="self" type="application/rss+xml"/> <description> <![CDATA[ chanshiyucx/blog Issues - Made with love by RSSHub(https://github.com/DIYgod/RSSHub) ]]> </description> <generator>RSSHub</generator> <webMaster>i@diygod.me (DIYgod)</webMaster> <language>zh-cn</language> <lastBuildDate>Thu, 26 Mar 2020 11:00:06 GMT</lastBuildDate> <ttl>60</ttl> <item> <title> <![CDATA[ Telegram 电报机器人 ]]> </title> <description> <![CDATA[ ]]> </description> <pubDate>Wed, 25 Mar 2020 03:54:04 GMT</pubDate> <guid isPermaLink="false">https://github.com/chanshiyucx/blog/issues/108</guid> <link>https://github.com/chanshiyucx/blog/issues/108</link>
其中的 <guid isPermaLink="false">
和 <link>
中的链接 github.com/chanshiyucx/blog/issues/ 替换为 chanshiyu.com/#/post/ 即可。于是还是同样的方法新建一个 Worker,然后修改一下 worker.js
的代码就可以啦。
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 // Website you intended to retrieve for users. const upstream = 'rsshub.app' // Custom pathname for the upstream website. const upstream_path = '/github/issue/chanshiyucx/blog' // Whether to use HTTPS protocol for upstream address. const https = true addEventListener('fetch', event => { event.respondWith(fetchAndApply(event.request)); }) async function fetchAndApply(request) { let response = null; let url = new URL(request.url); let url_hostname = url.hostname; if (https == true) { url.protocol = 'https:'; } else { url.protocol = 'http:'; } var upstream_domain = upstream; url.host = upstream_domain; if (url.pathname == '/') { url.pathname = upstream_path; } else { url.pathname = upstream_path + url.pathname; } 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; 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 }) let text = await response.text() // Modify it. let modified = text.replace(/github.com\/chanshiyucx\/blog\/issues\//g, "chanshiyu.com\/#\/post\/") // Return modified response. return new Response(modified, { status: response.status, statusText: response.statusText, headers: response.headers }) return response; }
部署好 Worker 之后就可以使用 RSS 来订阅啦😋