截止2023年7月,该方法可用,如果失效,我会告知。
众所周知的原因,Telegram的API在国内是用不了的,以前我用的是nginx的反代,但是最近把所有的vps都改为traefik了,又不想再弄一层nginx的反代,就研究了一下使用Cloudflare Worker来反代。反正白嫖的,不用白不用,一天100w次访问也足够个人使用了。
使用前提
1.一个托管在cloudflare的域名
2.开启cloudflare的免费worker服务
首先登录Cloudflare以后点击左侧的Workers
点击创建服务
服务名称随意填写,但是下面需要选择HTTP路由器
创建完成后,点击刚创建的Worker,再点击快速编辑
在左侧红框处删除原有的,填入下面给出的代码
/**
* Helper functions to check if the request uses
* corresponding method.
*
*/
const Method = (method) => (req) => req.method.toLowerCase() === method.toLowerCase();
const Get = Method('get');
const Post = Method('post');
const Path = (regExp) => (req) => {
const url = new URL(req.url);
const path = url.pathname;
return path.match(regExp) && path.match(regExp)[0] === path;
};
/*
* The regex to get the bot_token and api_method from request URL
* as the first and second backreference respectively.
*/
const URL_PATH_REGEX = /^\/bot(?<bot_token>[^/]+)\/(?<api_method>[a-z]+)/i;
/**
* Router handles the logic of what handler is matched given conditions
* for each request
*/
class Router {
constructor() {
this.routes = [];
}
handle(conditions, handler) {
this.routes.push({
conditions,
handler,
});
return this;
}
get(url, handler) {
return this.handle([Get, Path(url)], handler);
}
post(url, handler) {
return this.handle([Post, Path(url)], handler);
}
all(handler) {
return this.handler([], handler);
}
route(req) {
const route = this.resolve(req);
if (route) {
return route.handler(req);
}
const description = 'No matching route found';
const error_code = 404;
return new Response(
JSON.stringify({
ok: false,
error_code,
description,
}),
{
status: error_code,
statusText: description,
headers: {
'content-type': 'application/json',
},
}
);
}
/**
* It returns the matching route that returns true
* for all the conditions if any.
*/
resolve(req) {
return this.routes.find((r) => {
if (!r.conditions || (Array.isArray(r) && !r.conditions.length)) {
return true;
}
if (typeof r.conditions === 'function') {
return r.conditions(req);
}
return r.conditions.every((c) => c(req));
});
}
}
/**
* Sends a POST request with JSON data to Telegram Bot API
* and reads in the response body.
* @param {Request} request the incoming request
*/
async function handler(request) {
// Extract the URl method from the request.
const { url, ..._request } = request;
const { pathname: path, search } = new URL(url);
// Leave the first match as we are interested only in backreferences.
const { bot_token, api_method } = path.match(URL_PATH_REGEX).groups;
// Build the URL
const api_url = 'https://api.telegram.org/bot' + bot_token + '/' + api_method + search;
// Get the response from API.
const response = await fetch(api_url, _request);
const result = await response.text();
const res = new Response(result, _request);
res.headers.set('Content-Type', 'application/json');
return res;
}
/**
* Handles the incoming request.
* @param {Request} request the incoming request.
*/
async function handleRequest(request) {
const r = new Router();
r.get(URL_PATH_REGEX, (req) => handler(req));
r.post(URL_PATH_REGEX, (req) => handler(req));
const resp = await r.route(request);
return resp;
}
/**
* Hook into the fetch event.
*/
addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});
回到管理后台首页,点击左侧的“网站”,在右侧点击你已托管在Cloudflare的域名
选择该域名下的Workers
选择添加路由
在红框处填写你想要用的二级域名,比如:tgapi.test.com/* 注意后面必须是/*结尾,服务选择刚才创建的服务,环境选择production即可
最后保存就可以了。
现在可以替换掉你在任何地方使用telegram api的地址为https://tg.test.com了。
刚建完挺好的,过几天之后就这样了,为啥啊,ping域名发现会丢包。
curl https://tgbot.***/bot10687*****:AAAA/sendMessage?chat_id=1***&text=test
{“ok”:false,”error_code”:400,”description”:”Bad Request: message text is empty”}
Bad Request: message text is empty
意思是你发送的内容是空的,检查一下,另外可以自行手动请求看看返回结果。
CloudFlare workers.dev域名DNS污染被污染了,部署了之后不挂代理还是无法访问,我看网上说在dns中随便加一个解析记录,然后开启笑话就可以了
小花朵
要用你自己的域名而不是cf的域名
现在还能用吗
可以,至少我目前使用仍然正常
https://xxx/file/botxxx/file_path
这个api下载不了文件,头大
嗯,路径规则不匹配,我没用过下载文件,纯粹是用来发通知用的。你可以修改一下URL_PATH_REGEX的值,符合你的需求
请问我如何替换telebot中的接口地址?
看文章最后一句,将原本的 https://api.telegram.org 替换成 你的二级域名即可
不需要在worker的trigger那里,填写自定义二级域名吗?我填写了,倒是也能用。
完全按我这个走就好了,trigger我好像并没有配置
现在仍然可用,感谢教程
我试了,现在可以用,但是有个地方需要注意,我猜有部分人是用青龙, 在使用TG_API_HOST 处 不要加 http 或者 https
青龙的话:
系统设置-通知设置
最下面的 telegramBotApiHost
只需要填写域名即可
老大 现在还可以用吗 我还是不会搞
现在依然可用。当不可用的时候我会修改。
请问大佬有没有接触奥特曼机器人啊,我用的代码能在网页上正常给tgbot发消息,但是用在奥特曼反代链接机器人时,就用不起
没有用过,不知道是啥
大佬,部署完用浏览器访问替换后的链接,显示“403 Forbidden”,消息也发不出去,啥情况,证书也显示没有
直接访问域名当然不可行,还要带上botxxxx
搭完能用网页版Telegram吗?还是只能代API
能写个教程怎么用网页版手机版Telegram吗
这个只是可以用tg的bot api,推送消息。要使用软件本身,你需要搭v2ray一类的梯子,可参考我的v2ray docker项目。
那吗是要自己搭网站来用这API吗?有教程吗?
V2ray已有
这个api跟使用软件没啥关系,你要使用tg在手机端,那你手机需要装相关软件,比如ios需要美区账号购买并下载Shadowrocket。这个api是用于青龙面板或者你自己某些程序需要发送一些通知消息用的。
worker搭建后发消息一直提示{‘ok’: False, ‘error_code’: 400, ‘description’: ‘Bad Request: message text is empty’}
以下是我的python代码(域名已脱敏):
r = requests.post(f’https://tg.example.com/bot{token}/sendMessage’, json={“chat_id”: chat_id, “text”: “【机器人】测试消息”})
如果不替换API域名就可以正常发送
但是在浏览器访问https://tg.example.com/bot{token}/getMe可以正常返回bot信息
python我不太会,不过你可以手动命令行curl执行一下先看结果。目前你的情况是缺少text参数,所以应该是相关方法不对。
你用get 才行,post需要改进
目前的Works创建的时候没办法选择启动器为HTTP路由器类型了。咋办啊。这直接导致在给域名添加路由的时候没有环境的选项。导致没办法用。请问一下有什么办法解决吗?
现在直接添加works,然后快速编辑,修改代码,最后回到域名的works里就可以用了
post 的话 就会失败
{“ok”:false,”error_code”:404,”description”:”No matching route found”}
尽量使用post方式,另外,你请求的url不正确。
你这worker有问题
网上导出都是这个脚本,一直都是报错message is empty ,如果单纯curl没问题,感觉你这里没有把header带过去的样子还是怎么的,还有all的处理也是错误的handle多了个r
代码应该是没错的,我目前的青龙和其它的通知一直用的这个地址。不确定你用的是什么程序,用这个的话,所有参数都不能放header里,必须是以参数形式。
现在添加路由没有环境那一项了 怎么办
在青龙通知测试提示Error: {“ok”:false,”error_code”:400,”description”:”Bad Request: message text is empty”}
在青龙的“系统设置”-“通知设置”里
更新一下呗,2024年了
应该不用更新,还能用
/**
* GPT 修改后的版本
* 原版本:https://anerg.com/2022/07/25/reverse-proxy-telegram-bot-api-using-cloudflare-worker.html
* Post 会有问题:
* {“ok”:false,”error_code”:400,”description”:”Bad Request: message text is empty”}
*
* Helper functions to check if the request uses
* the corresponding method.
*/
const Method = (method) => (req) => req.method.toLowerCase() === method.toLowerCase();
const Get = Method(‘get’);
const Post = Method(‘post’);
const Path = (regExp) => (req) => {
const url = new URL(req.url);
const path = url.pathname;
return path.match(regExp) && path.match(regExp)[0] === path;
};
/*
* The regex to get the bot_token and api_method from the request URL
* as the first and second backreference respectively.
*/
const URL_PATH_REGEX = /^\/bot(?[^/]+)\/(?[a-z]+)/i;
/**
* Router handles the logic of what handler is matched given conditions
* for each request.
*/
class Router {
constructor() {
this.routes = [];
}
handle(conditions, handler) {
this.routes.push({
conditions,
handler,
});
return this;
}
get(url, handler) {
return this.handle([Get, Path(url)], handler);
}
post(url, handler) {
return this.handle([Post, Path(url)], handler);
}
all(handler) {
return this.handle([], handler);
}
route(req) {
const route = this.resolve(req);
if (route) {
return route.handler(req);
}
const description = ‘No matching route found’;
const error_code = 404;
return new Response(
JSON.stringify({
ok: false,
error_code,
description,
}),
{
status: error_code,
statusText: description,
headers: {
‘content-type’: ‘application/json’,
},
}
);
}
/**
* It returns the matching route that returns true
* for all the conditions if any.
*/
resolve(req) {
return this.routes.find((r) => {
if (!r.conditions || (Array.isArray(r) && !r.conditions.length)) {
return true;
}
if (typeof r.conditions === ‘function’) {
return r.conditions(req);
}
return r.conditions.every((c) => c(req));
});
}
}
/**
* Sends a POST request with JSON data to Telegram Bot API
* and reads in the response body.
* @param {Request} request the incoming request
*/
async function handler(request) {
// Extract the URL, method, and headers from the request
const { url, method, headers } = request;
// Parse the URL to get the pathname and search parameters
const { pathname: path, search } = new URL(url);
// Use regex to extract the bot token and API method from the path
const { bot_token, api_method } = path.match(URL_PATH_REGEX).groups;
// Construct the Telegram API URL
const api_url = ‘https://api.telegram.org/bot’ + bot_token + ‘/’ + api_method + search;
// Prepare the fetch options, including the method, headers, and body
const fetchOptions = {
method: method,
headers: headers,
};
// If it’s a POST request, clone the request to include the body
if (method.toUpperCase() === ‘POST’) {
const body = await request.text(); // Read the request body as text
fetchOptions.body = body; // Include the body in the fetch options
}
// Forward the request to the Telegram API
const response = await fetch(api_url, fetchOptions);
// Return the response to the client
const result = await response.text();
return new Response(result, {
status: response.status,
statusText: response.statusText,
headers: {
‘Content-Type’: ‘application/json’,
},
});
}
/**
* Handles the incoming request.
* @param {Request} request the incoming request.
*/
async function handleRequest(request) {
const r = new Router();
r.get(URL_PATH_REGEX, (req) => handler(req));
r.post(URL_PATH_REGEX, (req) => handler(req));
const resp = await r.route(request);
return resp;
}
/**
* Hook into the fetch event.
*/
addEventListener(‘fetch’, (event) => {
event.respondWith(handleRequest(event.request));
});
我这边尚未出现什么问题,用起来挺正常的
在青龙 v2.17.10上无法配置,去除https后提示非法的URL,麻烦看下
青龙里只填域名,比如 tgapi.xxx.com