Telegram Bot通过短轮询接收更新的开发教程

本文详细介绍Telegram Bot如何使用短轮询方式通过getUpdates方法接收用户消息与回调,包含API参数说明、代码示例、错误处理及最佳实践。

阅读提示建议先浏览小标题,再根据需要深入阅读具体段落。

在Telegram Bot开发中,接收用户消息和交互请求是构建一切功能的基础。Telegram Bot API提供了两种获取更新的方式:短轮询(Short Polling)长轮询(Long Polling)。尽管长轮询在现代开发中更常见,但理解短轮询的原理与实现,能让你更深刻地把握Bot的工作机制,并成为构建高效、稳定Bot的基石。本文将从零开始,手把手教你使用短轮询方式接收Telegram Bot的更新。

什么是短轮询?与长轮询的区别

短轮询是指客户端(你的Bot服务器)反复向Telegram服务器发送HTTP请求,询问是否有新的更新。每次请求都会立即得到响应——如果有更新,返回数据;如果没有,则返回空列表。长轮询则是在请求中设置timeout参数,Telegram服务器会保持连接直到有更新或超时才返回,从而减少无效请求。

短轮询的特点:

  • 实现简单:无需考虑长连接和超时机制。
  • 延迟相对较高:取决于轮询间隔。
  • 消耗更多资源:频繁请求可能触发速率限制。

尽管如此,短轮询在开发调试、低流量场景或需要完全控制请求节奏时依然有实用价值。学习它也能帮助你更好地理解偏移量(offset)和更新确认机制。

开发环境准备

在编写代码前,你需要完成以下准备工作:

  1. 创建Bot并获取Token:在Telegram中与@BotFather对话,使用/newbot命令创建一个新机器人,获得形如123456789:ABCdefGHI... 的API Token。
  2. 选择开发语言和库:你可以使用任何支持HTTP请求的语言。作为示例,我们使用Python(requests库)和Node.js(axios)展示两种常见实现。
  3. 了解getUpdates方法:这是轮询的核心API,文档位于https://api.telegram.org/bot<token>/getUpdates

getUpdates方法参数详解

getUpdates接受以下可选参数:

参数类型说明
offsetInteger第一个待确认更新的标识符。用于避免重复处理。
limitInteger每次最多返回的更新数量,1-100,默认100。
timeoutInteger长轮询超时秒数。短轮询通常设为0或不设置。
allowed_updatesArray指定要接收的更新类型,如["message","callback_query"]。

在短轮询模式下,我们不设置timeout(或设为0),请求立即返回。

使用短轮询获取更新的代码示例

Python实现(requests)

import requests

TOKEN = "你的BOT_TOKEN"
URL = f"https://api.telegram.org/bot/getUpdates"

def get_updates(offset=0):
    params = {"offset": offset, "timeout": 0}
    response = requests.get(URL, params=params)
    return response.json()

# 简单轮询循环
offset = 0
while True:
    data = get_updates(offset)
    for update in data.get("result", []):
        print(update)
        offset = update["update_id"] + 1

Node.js实现(axios)

const axios = require('axios');
const TOKEN = '你的BOT_TOKEN';
const URL = `https://api.telegram.org/bot$/getUpdates`;

async function getUpdates(offset = 0) {
    const { data } = await axios.get(URL, { params: { offset, timeout: 0 } });
    return data;
}

let offset = 0;
(async function startPolling() {
    while (true) {
        const data = await getUpdates(offset);
        for (const update of data.result || []) {
            console.log(update);
            offset = update.update_id + 1;
        }
    }
})();

上述代码中,每轮请求后我们更新offset为最新update_id + 1,确保Telegram服务器确认这些更新已被处理,下次不再返回。

处理更新数据

返回的result是一个更新对象数组。每个Update包含固定的update_id,以及根据更新类型不同的其他字段,常见的包括:

  • message:新的普通消息,包含message_idfrom(发送者)、chat(会话)、text(文本)等。
  • edited_message:消息被编辑。
  • channel_post:频道新帖子。
  • callback_query:按钮回调请求。

开发时可以根据实际业务需要,对不同类型的更新进行分派处理。例如:

if "message" in update:
    chat_id = update["message"]["chat"]["id"]
    text = update["message"].get("text", "")
    # 回复“收到”
    requests.post(f"https://api.telegram.org/bot/sendMessage", json={"chat_id": chat_id, "text": "收到:" + text})

轮询循环与错误处理

实际部署时,直接无限循环存在风险——网络异常、Telegram API限制等都会导致崩溃。因此需要加入错误处理:

import time
while True:
    try:
        data = get_updates(offset)
        if data.get("ok"):
            for update in data["result"]:
                process_update(update)
                offset = update["update_id"] + 1
    except Exception as e:
        print(f"请求出错: ")
        time.sleep(1)

特别要注意409 Conflict错误:当多个实例同时使用同一个Bot的getUpdates时会出现。确保同一时间只有一个轮询进程在运行。

另外,若请求过于频繁,可能收到429 Too Many Requestsretry_after字段。此时应等待指定时间再继续。

最佳实践与实用建议

  1. 始终使用offset:每次处理完更新后,立即更新offset并保存,以防崩溃导致重复或丢失。
  2. 设置合理的polling间隔:短轮询典型间隔为1-2秒。过短会骚扰服务器,过长则延迟高。若需要实时响应,建议升级为长轮询(设置timeout为30-50秒)。
  3. 使用allowed_updates过滤:只接收你关心的更新,减少带宽和处理压力。
  4. 代码结构模块化:将轮询逻辑与业务处理分离,方便后续维护和扩展。
  5. 使用Webhook替代:对于生产环境,更推荐Webhook模式——Telegram主动推送更新到你的HTTPS端点,效率更高。但短轮询和长轮询依然是本地开发和测试的好选择。

总结

通过本文的学习,你已经掌握了Telegram Bot短轮询接收更新的完整流程。虽然短轮询并非最高效的方案,但它清晰展示了getUpdates的核心机制——offset确认、更新对象解析和循环处理。理解这些概念后,你再转向长轮询或Webhook,将发现它们只是参数和网络模型上的变体。现在,启动你的第一个Bot,用短轮询亲手接收一条消息吧!

FAQ

多平台客户端选择

常见问题

短轮询和长轮询哪个更适合生产环境?

长轮询更合适。长轮询通过设置timeout参数,让Telegram服务器在有更新时立即返回,否则保持连接,减少了大量无效请求,降低了延迟和服务器负载。短轮询通常仅用于低频率场景或调试阶段。

如何避免短轮询导致409 Conflict错误?

409错误是因为多个实例同时调用同一Bot的getUpdates。确保整个运行环境中只有一个轮询进程。如果需要多进程,可以采用Webhook模式或为不同进程分配不同的offset区间(不推荐)。

为什么我收到的更新总是重复?

这通常是因为没有正确使用offset。每次处理完update后,必须将offset设置为该update的update_id + 1,并在下一次请求中传递。这样Telegram才知道你已经处理了这些更新,不会重复推送。

短轮询请求频率多快合适?

一般建议间隔1-2秒。过于频繁可能触发429限流,太慢则消息延迟。如果对实时性要求较高,建议改用长轮询(timeout=30~50),没有更新时连接保持,有更新时立即返回,既实时又省资源。