Python Slack App无法监听响应消息事件问题排查
Slack Python App 无消息响应故障排查
问题背景
- 参照Slack官方Python SDK教程开发Slack应用,推进至教程第4步中途时,应用无法对Slack工作区内发送的任何消息做出响应
- 已严格按照教程要求完成应用权限配置,所有权限配置与教程指引完全一致
- 本地启动应用时命令行提示
Bolt app is running! (development server),确认服务已在3000端口正常启动
应用完整代码
import logging from slack_bolt import App from slack_sdk.web import WebClient from onboarding_tutorial import OnboardingTutorial app = App(token="first secret token here", signing_secret="second secret token here") onboarding_tutorials_sent = {} def start_onboarding(user_id: str, channel: str, client: WebClient): # Create a new onboarding tutorial. onboarding_tutorial = OnboardingTutorial(channel) # Get the onboarding message payload message = onboarding_tutorial.get_message_payload() # Post the onboarding message in Slack response = client.chat_postMessage(**message) # Capture the timestamp of the message we've just posted so # we can use it to update the message after a user # has completed an onboarding task. onboarding_tutorial.timestamp = response["ts"] # Store the message sent in onboarding_tutorials_sent if channel not in onboarding_tutorials_sent: onboarding_tutorials_sent[channel] = {} onboarding_tutorials_sent[channel][user_id] = onboarding_tutorial # ================ Team Join Event =============== # # When the user first joins a team, the type of the event will be 'team_join'. # Here we'll link the onboarding_message callback to the 'team_join' event. # Note: Bolt provides a WebClient instance as an argument to the listener function # we've defined here, which we then use to access Slack Web API methods like conversations_open. # For more info, checkout: https://slack.dev/bolt-python/concepts#message-listening @app.event("team_join") def onboarding_message(event, client): """Create and send an onboarding welcome message to new users. Save the time stamp of this message so we can update this message in the future. """ # Get the id of the Slack user associated with the incoming event user_id = event.get("user", {}).get("id") # Open a DM with the new user. response = client.conversations_open(users=user_id) channel = response["channel"]["id"] # Post the onboarding message. start_onboarding(user_id, channel, client) # ============= Reaction Added Events ============= # # When a users adds an emoji reaction to the onboarding message, # the type of the event will be 'reaction_added'. # Here we'll link the update_emoji callback to the 'reaction_added' event. @app.event("reaction_added") def update_emoji(event, client): """Update the onboarding welcome message after receiving a "reaction_added" event from Slack. Update timestamp for welcome message as well. """ # Get the ids of the Slack user and channel associated with the incoming event channel_id = event.get("item", {}).get("channel") user_id = event.get("user") if channel_id not in onboarding_tutorials_sent: return # Get the original tutorial sent. onboarding_tutorial = onboarding_tutorials_sent[channel_id][user_id] # Mark the reaction task as completed. onboarding_tutorial.reaction_task_completed = True # Get the new message payload message = onboarding_tutorial.get_message_payload() # Post the updated message in Slack updated_message = client.chat_update(**message) # =============== Pin Added Events ================ # # When a users pins a message the type of the event will be 'pin_added'. # Here we'll link the update_pin callback to the 'pin_added' event. @app.event("pin_added") def update_pin(event, client): """Update the onboarding welcome message after receiving a "pin_added" event from Slack. Update timestamp for welcome message as well. """ # Get the ids of the Slack user and channel associated with the incoming event channel_id = event.get("channel_id") user_id = event.get("user") # Get the original tutorial sent. onboarding_tutorial = onboarding_tutorials_sent[channel_id][user_id] # Mark the pin task as completed. onboarding_tutorial.pin_task_completed = True # Get the new message payload message = onboarding_tutorial.get_message_payload() # Post the updated message in Slack updated_message = client.chat_update(**message) # ============== Message Events ============= # # When a user sends a DM, the event type will be 'message'. # Here we'll link the message callback to the 'message' event. @app.event("message") def message(event, client): """Display the onboarding welcome message after receiving any message """ channel_id = event.get("channel") user_id = event.get("user") text = event.get("text") return start_onboarding(user_id, channel_id, client) if __name__ == "__main__": logger = logging.getLogger() logger.setLevel(logging.DEBUG) logger.addHandler(logging.StreamHandler()) app.start(3000)
命令行运行记录
Microsoft Windows [Version 10.0.19041.388] (c) 2020 Microsoft Corporation. All rights reserved. C:\Users\sprogissd>cd pycharmprojects/pythonproject C:\Users\sprogissd\PycharmProjects\pythonProject>python3 app.py Bolt app is running! (development server)
故障原因与修复方案
本地3000端口服务启动正常但完全收不到Slack事件,核心原因是本地运行的服务处于内网,没有公网可访问的入口,Slack无法将工作区的事件推送到你的本地服务,大概率是跳过了教程第4步要求的内网穿透配置,或是配置后未正确填写回调地址。
按以下步骤逐一排查修复:
- 配置内网穿透隧道:启动ngrok工具,执行命令
ngrok http 3000,拿到工具分配的https://<随机字符>.ngrok.io格式公网地址 - 配置Slack回调地址:进入Slack应用管理后台的Event Subscriptions页面,打开事件订阅开关,将Request URL填写为
https://<你的ngrok公网地址>/slack/events,等待Slack自动完成地址校验,校验通过后会显示绿色对勾标识 - 确认事件订阅范围:在Event Subscriptions页面的Subscribe to bot events板块,确认已添加代码中用到的所有事件类型:
team_join、message.channels、message.im、reaction_added、pin_added,保存配置后重新将应用安装到对应工作区 - 校验凭证正确性:确认代码中填写的
token为应用的Bot User OAuth Token,signing_secret为应用Basic Information页面的Signing Secret,两类凭证填混会导致Slack请求签名校验失败,应用不会处理任何推送事件
注意事项:ngrok免费版每次重启都会更换分配的公网地址,每次重启ngrok后都需要到Slack后台更新Request URL配置。配置正确的前提下,Slack推送事件到本地服务时,运行app.py的命令行会打印DEBUG级别的请求接收日志,不会仅显示启动提示。
内容的提问来源于stack exchange,提问作者sprogissd
相关产品推荐
相关产品推荐

