飞书机器人消息通道SDK配置教程
背景说明
在使用轻量应用服务器一键部署飞书应用时,飞书配置会被保留。但在本地部署时,会遇到一个常见问题:无法直接建立长连接,系统提示"没有检测到可用的信息管道"。
以下是通过飞书SDK配置解决此问题的记录。
环境要求
- Python版本:3.13(本教程基于此版本,其他Python 3.x版本也可)
- 操作系统:Windows/Linux/MacOS均可

方法一:直接使用pip安装(推荐)
以管理员身份打开终端(Windows)或使用sudo(Linux/Mac),执行以下命令:
bash
pip install lark-oapi -U
方法二:源码安装
-
从GitHub下载SDK源码:
text
arduinohttps://github.com/larksuite/oapi-sdk-python -
进入下载目录,执行安装:
bash
arduinopython setup.py install
第二步:配置Python脚本
完整脚本代码
创建一个Python文件,例如lark_client.py,将以下代码复制进去:
由于飞书文档有点复杂,建议直接使用以下整理后的脚本
python
import lark_oapi as lark
import threading
import logging
import time
from dataclasses import dataclass
# ==================== 日志配置 ====================
# 配置日志系统,方便追踪程序运行状态
logging.basicConfig(
level=logging.INFO, # 设置日志级别为INFO
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' # 日志格式:时间-名称-级别-消息
)
logger = logging.getLogger(__name__) # 创建主日志记录器
# ==================== 数据模型 ====================
@dataclass
class ClientConfig:
"""
客户端配置数据类
使用dataclass简化配置对象的创建和管理
"""
app_id: str # 飞书应用的App ID
app_secret: str # 飞书应用的App Secret
name: str # 客户端名称,用于区分多个客户端
reconnect_attempts: int = 3 # 断线重连尝试次数,默认3次
reconnect_delay: int = 5 # 重连间隔时间(秒),默认5秒
# ==================== 消息处理器 ====================
class MessageHandler:
"""
消息处理器类
负责处理接收到的各种类型消息,将处理逻辑与客户端分离
"""
def __init__(self, client_name: str):
"""
初始化消息处理器
:param client_name: 客户端名称,用于日志标识
"""
self.client_name = client_name
# 为每个客户端创建独立的日志记录器
self.logger = logging.getLogger(f"MessageHandler-{client_name}")
def handle_p2_message(self, data: lark.im.v1.P2ImMessageReceiveV1) -> None:
"""
处理P2消息(消息v2.0版本)
这是飞书最新的消息格式
:param data: 接收到的消息数据对象
"""
try:
# 将消息对象转换为格式化的JSON字符串
message_data = lark.JSON.marshal(data, indent=4)
self.logger.info(f"收到P2消息: {message_data}")
# 打印消息到控制台,保持与原代码相同的输出格式
print(f'[{self.client_name}] [P2消息] data: {message_data}')
except Exception as e:
self.logger.error(f"处理P2消息失败: {e}")
def handle_custom_event(self, data: lark.CustomizedEvent) -> None:
"""
处理自定义事件(包括消息v1.0版本)
用于兼容旧版本的消息格式
:param data: 接收到的自定义事件对象
"""
try:
event_data = lark.JSON.marshal(data, indent=4)
self.logger.info(f"收到自定义事件: {event_data}")
print(f'[{self.client_name}] [自定义事件] data: {event_data}')
except Exception as e:
self.logger.error(f"处理自定义事件失败: {e}")
# ==================== 事件处理器工厂 ====================
def create_event_handlers(handler: MessageHandler):
"""
创建事件处理器函数
使用闭包方式将MessageHandler实例传递给处理器
:param handler: 消息处理器实例
:return: 包含两个处理器函数的元组
"""
def p2_message_handler(data: lark.im.v1.P2ImMessageReceiveV1) -> None:
"""P2消息处理器闭包"""
handler.handle_p2_message(data)
def custom_event_handler(data: lark.CustomizedEvent) -> None:
"""自定义事件处理器闭包"""
handler.handle_custom_event(data)
return p2_message_handler, custom_event_handler
# ==================== 客户端管理 ====================
class LarkClient:
"""
飞书客户端管理类
封装客户端的创建、启动和重连逻辑
"""
def __init__(self, config: ClientConfig):
"""
初始化客户端
:param config: 客户端配置对象
"""
self.config = config
self.logger = logging.getLogger(f"LarkClient-{config.name}")
self.client = None # 客户端实例,初始为None
self.running = False # 运行状态标志
def create_client(self) -> lark.ws.Client:
"""
创建并配置飞书WebSocket客户端
:return: 配置好的客户端实例
"""
# 创建消息处理器
handler = MessageHandler(self.config.name)
# 获取事件处理器函数
p2_handler, custom_handler = create_event_handlers(handler)
# 构建事件分发器
# builder("", "") 中的参数是加密密钥和验证令牌,这里使用空字符串
event_handler = lark.EventDispatcherHandler.builder("", "") \
.register_p2_im_message_receive_v1(p2_handler) \
.register_p1_customized_event("url_verification", custom_handler) \
.build()
# 创建WebSocket客户端
client = lark.ws.Client(
app_id=self.config.app_id,
app_secret=self.config.app_secret,
event_handler=event_handler,
log_level=lark.LogLevel.INFO # 设置SDK日志级别
)
return client
def start_with_reconnect(self):
"""
启动客户端并实现断线重连机制
当连接断开时自动尝试重新连接
"""
attempt = 1
while attempt <= self.config.reconnect_attempts:
try:
self.logger.info(f"正在启动客户端 (尝试 {attempt}/{self.config.reconnect_attempts})...")
# 创建并启动客户端
self.client = self.create_client()
self.running = True
# 客户端启动(这会阻塞,直到连接断开)
self.client.start()
# 如果start()返回,说明连接已断开
self.running = False
self.logger.warning(f"客户端连接已断开")
# 如果还有重试机会,等待后重试
if attempt < self.config.reconnect_attempts:
self.logger.info(f"{self.config.reconnect_delay}秒后进行重连...")
time.sleep(self.config.reconnect_delay)
attempt += 1
else:
self.logger.error("已达到最大重连次数,停止重试")
break
except Exception as e:
self.logger.error(f"客户端运行出错: {e}")
self.running = False
if attempt < self.config.reconnect_attempts:
self.logger.info(f"{self.config.reconnect_delay}秒后进行重连...")
time.sleep(self.config.reconnect_delay)
attempt += 1
else:
self.logger.error("已达到最大重连次数,停止重试")
break
def stop(self):
"""停止客户端运行"""
self.logger.info("正在停止客户端...")
self.running = False
if self.client:
# 这里可以添加客户端的停止逻辑
# 具体取决于lark_oapi库是否提供停止方法
pass
# ==================== 主程序 ====================
def main():
"""
主函数:配置并启动多个飞书客户端
每个客户端在独立的线程中运行
"""
# 客户端配置列表
# 可以配置多个客户端,每个使用不同的App ID和Secret
clients_config = [
ClientConfig(
app_id="", # 请替换为实际的App ID
app_secret="", # 请替换为实际的App Secret
name="Client-1", # 客户端名称
reconnect_attempts=3, # 重连尝试次数
reconnect_delay=5 # 重连延迟(秒)
)
# 可以在这里添加更多客户端配置
# ClientConfig(app_id="xxx", app_secret="xxx", name="Client-2"),
]
# 验证配置是否完整
for config in clients_config:
if not config.app_secret:
logger.warning(f"客户端 {config.name} 的 App Secret 为空,请设置正确的密钥")
# 创建并启动客户端线程
threads = [] # 存储所有线程
clients = [] # 存储所有客户端实例,用于可能的后续控制
for config in clients_config:
# 为每个配置创建客户端实例
client = LarkClient(config)
clients.append(client)
# 创建守护线程运行客户端
# daemon=True 确保主程序退出时线程自动结束
thread = threading.Thread(
target=client.start_with_reconnect, # 线程要执行的函数
name=f"Thread-{config.name}", # 线程名称
daemon=True # 设置为守护线程
)
threads.append(thread)
thread.start() # 启动线程
logger.info(f"已启动客户端 {config.name} 的线程")
logger.info("所有客户端已启动,按 Ctrl+C 退出...")
# 保持主线程运行,等待所有子线程
try:
# join() 会阻塞直到线程结束
# 由于线程是守护线程且无限运行,这里实际上会一直阻塞
for thread in threads:
thread.join()
except KeyboardInterrupt:
# 捕获Ctrl+C,优雅退出
logger.info("接收到中断信号,正在关闭所有客户端...")
# 通知所有客户端停止
for client in clients:
client.stop()
logger.info("所有客户端已关闭")
# ==================== 程序入口 ====================
# 程序入口点:只有在直接运行此脚本时才会执行 main()
if __name__ == "__main__":
main()
配置机器人信息
在脚本中找到main()函数中的clients_config列表,填写您的飞书应用信息:
python
ini
clients_config = [
ClientConfig(
app_id="您的App ID", # 例如:cli_xxxxx
app_secret="您的App Secret", # 例如:xxxxxx
name="Client-1", # 自定义客户端名称
reconnect_attempts=3, # 重连尝试次数
reconnect_delay=5 # 重连延迟(秒)
)
]
如何获取App ID和App Secret?
- 登录飞书开放平台
- 进入"开发者后台"
- 选择您的应用
- 在"凭证与基础信息"页面即可看到App ID和App Secret
第三步:运行脚本
在终端中执行:
bash
python lark_client.py
运行成功后,您将看到类似以下的日志输出:
text
arduino
2025-01-20 10:30:15 - LarkClient-Client-1 - INFO - 正在启动客户端 (尝试 1/3)...
2025-01-20 10:30:16 - LarkClient-Client-1 - INFO - 已启动客户端 Client-1 的线程
2025-01-20 10:30:16 - root - INFO - 所有客户端已启动,按 Ctrl+C 退出...
第四步:验证配置
- 保持脚本运行状态
- 刷新飞书开放平台
- 进入您的应用
- 在"事件订阅"或"机器人"配置页面
- 此时应该可以看到连接状态变为"已连接"或类似状态
![连接成功示意图]
第五步:发布应用
重要提醒 :修改机器人配置后,必须发布新版本才能使配置生效!
常见问题
Q1: 连接失败,提示"App ID或App Secret错误"
解决方案:
- 检查App ID和App Secret是否填写正确
- 确认应用是否处于"启用"状态
- 确认应用的权限配置是否正确
Q2: 连接成功后收不到消息
解决方案:
- 确认已在飞书开放平台配置了事件订阅
- 检查事件订阅中是否勾选了需要接收的消息类型
- 查看脚本日志,确认是否有消息进入
Q3: 脚本运行一段时间后自动断开
解决方案 :
脚本已内置自动重连机制,默认尝试3次,每次间隔5秒。如需调整,可修改配置:
python
ini
ClientConfig(
# ... 其他配置
reconnect_attempts=5, # 增加重连次数
reconnect_delay=3 # 减少重连间隔
)
Q4: 如何同时运行多个机器人?
在clients_config列表中添加多个配置即可:
python
ini
clients_config = [
ClientConfig(app_id="xxx1", app_secret="xxx1", name="机器人1"),
ClientConfig(app_id="xxx2", app_secret="xxx2", name="机器人2"),
# 可以继续添加
]