小黑屋 · 2022年7月25日 37

使用Cloudflare Worker代理Telegram Bot Api

截止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了。