如何为已发送消息添加Inline Keyboard?及回调中原键盘获取方案咨询
Short answer: No, you can't directly get the original InlineKeyboardMarkup from the Message object included in a CallbackQuery. As you noted, the Telegram Bot API intentionally excludes the reply_markup field from this message payload to cut down on unnecessary data transfer.
But don't worry—there are solid workarounds to handle this scenario. Here are the most practical options:
1. Store the keyboard data locally when sending the message
This is the most reliable approach. When you send a message with an inline keyboard, save the keyboard's structure alongside the message's unique identifier (a combination of chat_id and message_id works perfectly as a key) in a database, in-memory cache (like Redis), or even a simple in-memory dictionary (for small, non-distributed bots).
When you receive a CallbackQuery, use the chat_id and message_id from the query's message object to look up the stored keyboard data.
Example (using Python with python-telegram-bot):
# Initialize a simple in-memory cache (replace with Redis/database for production) keyboard_cache = {} # When sending the message with inline keyboard def send_message_with_keyboard(bot, user_id): keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton("First Button", callback_data="btn1")], [InlineKeyboardButton("Second Button", callback_data="btn2")] ]) sent_msg = bot.send_message(chat_id=user_id, text="Choose an option:", reply_markup=keyboard) # Store the keyboard using chat_id + message_id as the key cache_key = f"{sent_msg.chat.id}:{sent_msg.message_id}" keyboard_cache[cache_key] = keyboard.to_dict() # Handling the CallbackQuery @bot.callback_query_handler(func=lambda call: True) def handle_callback(call): cache_key = f"{call.message.chat.id}:{call.message.message_id}" stored_keyboard_data = keyboard_cache.get(cache_key) if stored_keyboard_data: # Reconstruct the InlineKeyboardMarkup object original_keyboard = InlineKeyboardMarkup.de_json(stored_keyboard_data) # Now you can use original_keyboard for edits, checks, etc. print("Original keyboard retrieved:", original_keyboard)
2. Encode keyboard data into callback_data
If your inline keyboard is relatively simple (no overly complex nested structures), you can encode a simplified version of the keyboard into each button's callback_data. Just make sure to stay within the 64-byte limit for callback_data.
You can serialize the keyboard data to JSON, then encode it to Base64 to save space. When the button is clicked, decode the data from the callback_data to reconstruct the keyboard.
Example:
import json import base64 def send_encoded_keyboard(bot, user_id): # Define the keyboard structure as a plain dict keyboard_structure = { "buttons": [ ["First Button", "btn1"], ["Second Button", "btn2"] ] } # Serialize and encode serialized = json.dumps(keyboard_structure).encode() encoded_data = base64.b64encode(serialized).decode() # Combine with an action identifier (keep total length under 64) callback_data = f"action|{encoded_data}" if len(callback_data) > 64: # Handle overflow (simplify the structure or use another method) raise ValueError("Encoded data too long for callback_data") # Build the keyboard keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(text, callback_data=f"action|{encoded_data}") for text, _ in row] for row in keyboard_structure["buttons"] ]) bot.send_message(chat_id=user_id, text="Choose:", reply_markup=keyboard) @bot.callback_query_handler(func=lambda call: call.data.startswith("action|")) def handle_encoded_callback(call): _, encoded_data = call.data.split("|", 1) # Decode and reconstruct serialized = base64.b64decode(encoded_data).decode() keyboard_structure = json.loads(serialized) original_keyboard = InlineKeyboardMarkup([ [InlineKeyboardButton(text, data) for text, data in row] for row in keyboard_structure["buttons"] ]) print("Reconstructed keyboard:", original_keyboard)
3. Fetch the original message (not recommended)
You could use the getChatHistory or getMessage API methods to retrieve the full original message, which includes the reply_markup. However, this approach has major downsides:
- If the user deleted the message, you won't be able to fetch it.
- Your bot needs the appropriate permissions to access chat history.
- Frequent API calls can lead to rate limiting, which disrupts bot performance.
This should only be used as a last-resort fallback, not a primary solution.
内容的提问来源于stack exchange,提问作者Ivan Vinogradov

