在 Vercel 上部署 Telegram Bot
2023-10-28 20:35+0800
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 模式:
curl "https://api.telegram.org/bot{token}/setWebhook?url={webhook}"
此时我们假定我们已经设定的 Tunnel 跑在 bot-test.ooze.gq,则应该执行
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. 部署
我懒得写了,你看着办吧