基于Google Apps Script的Telegram机器人Inline按钮重复响应问题
问题描述
我用Google Apps Script搭建了一个Telegram机器人,通过Webhook处理更新。点击Inline按钮时,机器人能返回正确回复,但每隔1-2分钟会重复发送相同响应,用户并未再次点击。
日志分析显示,Telegram重复发送同一callback_query的原因是脚本未及时返回HTTP 200 OK,或未快速调用answerCallbackQuery。我尝试返回ContentService.createTextOutput()并发送200 OK响应,但问题仍存在。如何确保每次按钮点击仅触发一次响应,避免无限重复?
代码示例
function installBot() { const res = UrlFetchApp.fetch(`${API_URL}/setWebhook?url=${WEB_APP_URL}`); Logger.log(res.getContentText()); } function doPost(e) { const update = JSON.parse(e.postData.contents); Logger.log(update); if (update.message) handleMessage(update.message); else if (update.callback_query) handleCallback(update.callback_query); return ContentService.createTextOutput("OK"); } function handleMessage(msg) { const chatId = msg.chat.id; const text = msg.text ? msg.text.trim().toLowerCase() : ""; switch (text) { case "/start": sendMainMenu(chatId); break; ... default: sendText(chatId, "❌ Commande inconnue.\nEssayez /start ou /help."); } } function handleCallback(query) { const chatId = query.message.chat.id; const data = query.data; const queryId = query.id; let replyText = ""; UrlFetchApp.fetch(`${API_URL}/answerCallbackQuery`, { method: "post", contentType: "application/json", payload: JSON.stringify({ callback_query_id: queryId, text: "", show_alert: false }), }); switch (data) { case "trial": replyText = "⚠️ Option inconnue."; break; ... } if (replyText) { sendMessage(chatId, replyText, { parse_mode: "HTML" }); } } function sendText(chatId, text, mode = "HTML") { const url = `${API_URL}/sendMessage`; const payload = { method: "post", contentType: "application/json", payload: JSON.stringify({ chat_id: chatId, text: text, parse_mode: mode, }), }; UrlFetchApp.fetch(url, payload); } function sendMessage(chatId, text, options) { const url = `${API_URL}/sendMessage`; const payload = { method: "post", contentType: "application/json", payload: JSON.stringify({ chat_id: chatId, text: text, ...options, }), }; UrlFetchApp.fetch(url, payload); }
解决方案
1. 异步处理耗时操作,优先返回200 OK
Google Apps Script的doPost函数如果同步执行UrlFetchApp等耗时操作,会延迟返回响应,导致Telegram判定请求超时并重复发送callback_query。需先快速返回200,再通过触发器异步处理业务逻辑:
修改doPost函数并新增异步处理函数:
function doPost(e) { const update = JSON.parse(e.postData.contents); Logger.log(update); // 创建异步触发器,延迟1秒执行处理逻辑 const trigger = ScriptApp.newTrigger("processUpdate") .timeBased() .after(1000) .create(); // 将update数据存入缓存,供异步函数读取 CacheService.getScriptCache().put(trigger.getUniqueId(), JSON.stringify(update), 60); // 立即返回200 return ContentService.createTextOutput("OK").setMimeType(ContentService.MimeType.TEXT); } // 异步处理更新逻辑 function processUpdate(e) { const triggerId = e.triggerUid; const update = JSON.parse(CacheService.getScriptCache().get(triggerId)); // 删除触发器,释放资源 ScriptApp.deleteTrigger(ScriptApp.getTriggerById(triggerId)); if (update.message) handleMessage(update.message); else if (update.callback_query) handleCallback(update.callback_query); }
2. 添加callback_query去重机制
用CacheService记录已处理的callback_query_id,避免重复响应:
修改handleCallback函数:
function handleCallback(query) { const queryId = query.id; const cache = CacheService.getScriptCache(); // 检查该query是否已处理,已处理则直接返回 if (cache.get(queryId)) return; // 标记为已处理,缓存10分钟(覆盖Telegram重试周期) cache.put(queryId, "processed", 600); const chatId = query.message.chat.id; const data = query.data; let replyText = ""; // 优先调用answerCallbackQuery,确保10秒内完成 UrlFetchApp.fetch(`${API_URL}/answerCallbackQuery`, { method: "post", contentType: "application/json", payload: JSON.stringify({ callback_query_id: queryId, text: "", show_alert: false }), muteHttpExceptions: true // 避免请求失败中断执行 }); switch (data) { case "trial": replyText = "⚠️ Option inconnue."; break; ... } if (replyText) { sendMessage(chatId, replyText, { parse_mode: "HTML" }); } }
3. 优化UrlFetchApp调用
给UrlFetchApp.fetch添加超时设置,并开启静默异常,避免因网络问题导致整个函数中断:
修改sendText和sendMessage函数:
function sendText(chatId, text, mode = "HTML") { const url = `${API_URL}/sendMessage`; const payload = { method: "post", contentType: "application/json", payload: JSON.stringify({ chat_id: chatId, text: text, parse_mode: mode, }), muteHttpExceptions: true, timeout: 5000 // 设置5秒超时 }; UrlFetchApp.fetch(url, payload); } function sendMessage(chatId, text, options) { const url = `${API_URL}/sendMessage`; const payload = { method: "post", contentType: "application/json", payload: JSON.stringify({ chat_id: chatId, text: text, ...options, }), muteHttpExceptions: true, timeout: 5000 // 设置5秒超时 }; UrlFetchApp.fetch(url, payload); }
内容的提问来源于stack exchange,提问作者Joey Perkins
相关产品推荐
相关产品推荐

