koto's Site # 😜 Knowing me Shorts Search Posts Tags Dates Friends Settings

在 Vercel 上部署 Telegram Bot

如何在 Vercel 平台上部署一个 Serverless Telegram Bot

2023-10-28 12:35:00 (UTC) 3 mins 40 s

Tagged with:

1. 申请 Bot

先在 BotFather 申请一个 Bot,输入 bot 的显示名称和 ID 拿到 Bot Token.

Bot Token 大概长这样子:

66XXXXXX88:AAAAAQQQeeefffpppaaalllnnnppp111ooo

拿到新鲜的 Bot Token 之后取出备用。

2. 设定 Webhook

Telegram bot 有两种获取讯息的方式:

Polling(轮询)模式。即 bot 每隔一段时间向 Telegram 服务器拉取讯息。

Webhook 模式。即 Telegram 服务器在收取到讯息的时候向指定的 Webhook 地址发送请求。

由于 Vercel Serverless Function 的特殊性质,我们只能使用 Webhook。 或者说我太低能不会拿 Vercel Serverless Function 写 Polling 模式的 Serverless Bot

为了方便调试,我们需要在本地设定一个 Cloudflare Tunnel,你可以查看这篇博文学到更多:设定 Cloudflare Tunnel

通过 Telegram API 将 Bot 设定为 Webhook 模式:

Terminal window
curl "https://api.telegram.org/bot{token}/setWebhook?url={webhook}"

此时我们假定我们已经设定的 Tunnel 跑在 bot-test.ooze.gq,则应该执行

Terminal window
curl "https://api.telegram.org/bot66XXXXXX88:AAAAAQQQeeefffpppaaalllnnnppp111ooo/setWebhook?url=https://bot-test.ooze.gq/api/webhook"

如果你收到类似 {"ok":true,"result":true,"description":"Webhook was set"} 的返回结果,则为设置成功。

3. 开发

3.1 回声机器人

执行 mkdir Vercel-Telegram-Bot && cd Vercel-Telegram-Bot 创建并切换到工作目录.

执行 pnpm i node-telegram-bot-api 安装必要的依赖.

执行 mkdir api && touch webhook.js 创建 webhook api.

选择你喜欢的编辑器开始编辑 webhook.js ,下面是一个简单的回声机器人的示范:

const TelegramBot = require("node-telegram-bot-api");
module.exports = async (request, response) => {
try {
const bot = new TelegramBot(process.env.TELEGRAM_TOKEN);
const { body } = request;
const { chat: { id }, text } = body.message;
// Echo Bot Example:
if (body.message.chat.type === "private" && body.message) {
await bot.sendMessage(id, `You have sent **"${text}"**!`, { parse_mode: "Markdown" });
}
}
catch (error) {
console.error("Error to sending message, " + error.toString());
}
response.send("OK");
};

接下来使用 TELEGRAM_TOKEN="66XXXXXX88:AAAAAQQQeeefffpppaaalllnnnppp111ooo" vercel dev 启动开发服务器

如果你以上操作的执行正确,向你的 Bot 发送 /start,此时你应该就会收到 You have sent "/start"!

3.2 接入 hitokoto API 示例

由于是 bot, 可能会被用在群里,我们添加一段指令:

const username = process.env.TELEGRAM_BOT_USERNAME || `@${await bot.getMe().username}`;

这回优先从环境变量 TELEGRAM_BOT_USERNAME 中获取 Bot 的 username, 如果没有则自动获取。

判断 /hitokoto 指令:

if (
text.toString().startsWith("/hitokoto ") ||
text.toString() === "/hitokoto" ||
text.toString().startsWith(`/hitokoto@${username}`)
) {
// do your job
}

接下来使用 fetch 从 hitokoto 获取并处理数据:

let hitokotoText = await fetch(`https://v1.hitokoto.cn/?t=${new Date().getTime()}`)
.then(res => res.json())
.then(res => {
return `「 ${res.hitokoto} 」 \n` +
`來自${res.from_who ? res.from_who + "的" : ""}「 ${res.from} 」`;
})
.catch(() => {
return "API 或者 Bot 爆炸了捏😋"
})

最后发送:

await bot.sendMessage(id, hitokotoText, { parse_mode: "Markdown" });

汇总如下:

const TelegramBot = require("node-telegram-bot-api");
module.exports = async (request, response) => {
try {
const bot = new TelegramBot(process.env.TELEGRAM_TOKEN);
const username = process.env.TELEGRAM_BOT_USERNAME || `@${await bot.getMe().username}`;
const { body } = request;
const { chat: { id }, text } = body.message;
console.log(text)
// Hitokoto Bot Example:
if (
text.toString().startsWith("/hitokoto ") ||
text.toString() === "/hitokoto" ||
text.toString().startsWith(`/hitokoto@${username}`)
) {
let hitokotoText = await fetch(`https://v1.hitokoto.cn/?t=${new Date().getTime()}`)
.then(res => res.json())
.then(res => {
return `「 ${res.hitokoto} 」 \n` +
`來自${res.from_who ? res.from_who + "的" : ""}「 ${res.from} 」`;
})
.catch(() => {
return "API 或者 Bot 爆炸了捏😋"
})
await bot.sendMessage(id, hitokotoText, { parse_mode: "Markdown" })
}
}
catch (error) {
console.error("Error to sending message, " + error.toString());
}
response.send("OK");
};

4. 部署

我懒得写了,你看着办吧

# 在 Vercel 上部署 Telegram Bot