☰
飞书长连接事件订阅实战:本机5分钟跑通,生产要补两块
2026/10/17 6:52:35 网站建设 项目流程

这是「飞书对接」小专题的第1篇,共5篇,从《MCP实战手记(十一):MCP接飞书,从机器人到事件订阅的三层深度接入》延伸(对应正文第3层事件订阅)。

让店长在飞书群里@机器人查门店数据,机器人第一步得"收得到"群消息。收消息有公网回调和长连接两条路。这篇讲清为什么长连接更适合个人/小团队:免公网入站端口、免内网穿透、免域名证书,本机只需出站连wss://msg-frontier.feishu.cn即可建连;并澄清"免公网入站 ≠ 不需要公网"的边界。给出 EventDispatcher + ws.Client 建连代码、五个必踩的坑,以及生产化两件必做事:event_id幂等(平台重投)与多实例Redis分发。

一、收消息的两条路

公网回调这条路,飞书把服务地址登记成"事件订阅回调URL",有人@机器人时,飞书服务器向这个URL发POST。问题全在这条URL上:

  • 必须HTTPS:飞书不收裸http回调地址,得有证书。
  • 必须稳定:用ngrok/cpolar内网穿透,免费域名每次重启都变,得回飞书后台反复改回调地址。
  • 暴露在公网,意味着得自己先做签名校验防伪造,否则谁都能往端点POST假事件。

小团队为了"收个群消息"要凑齐公网IP/域名/证书/穿透/签名校验,门槛直接劝退。

长连接(WebSocket)反过来:本机只需出站连wss://msg-frontier.feishu.cn,用App ID/Secret换access_token后建连。飞书把事件"推"进这条长连接,入站端口、域名、证书、穿透统统不用管。

边界澄清:免公网入站 ≠ 不需要公网。长连接只是把"入站收POST"换成"出站建 WS"。本机若在完全离线内网仍收不到;能跑通的前提是能出站访问飞书。这点别被"免公网"误导成"拔网线也能用"。

二、长连接怎么建(Java SDK实测)

核心就一个EventDispatcher收事件 + 一个ws.Client建长连接。注意SDK坐标定案:com.larksuite.oapi:oapi-sdk:2.3.4(不是官方文档写的com.lark.oapi:lark-oapi-sdk,长连接客户端类路径不同)。

//主API客户端:全限定名!避免与ws.Client同名冲突(踩坑1)importcom.larksuite.oapi.client.Client;importcom.larksuite.oapi.client.ClientImpl;importcom.larksuite.oapi.event.EventDispatcher;importcom.larksuite.oapi.ws.Client;// 长连接客户端(注意坐标:com.larksuite.oapi)importcom.larksuite.oapi.ws.ClientImpl;importcom.larksuite.oapi.event.message.MessageReceiveEventHandler;ClientapiClient=newClientImpl.Builder("app_id","app_secret",newCache()).build();// 事件订阅用应用级 token,不是tenant_access_tokenClientwsClient=newClientImpl.Builder("app_id","app_secret",newCache(),newEventDispatcher().registerMessageReceiveEventHandler(newMessageReceiveEventHandler(){@Overridepublicvoidhandle(MessageReceiveEventevent){/* 剥@、解析意图、调MCP */}})).build();wsClient.start();// 出站连 wss://msg-frontier.feishu.cn

收到im.message.receive_v1(单聊+群@),剥掉@提及、解析意图、按门店调MCP工具、回卡片——一条WebSocket把"群里@机器人→调@Tool→回卡片"闭环打通。

三、五个必踩的坑

  1. Client同名冲突(最关键):com.lark.oapi.Client(API)与com.lark.oapi.ws.Client(WS)都叫Client,两个single-type import 会冲突,API客户端必须全限定名。官方demo用com.lark.oapi坐标,但长连接SDK是com.larksuite.oapi,两者混用必炸。
  2. 事件权限未携:@机器人、消息、群聊等事件要先在开发者后台「事件订阅」勾选,漏了收不到;且长连接通道与回调URL 二选一,开了回调 URL 长连接就不投递。
  3. 发布后约1分钟延迟(飞书FAQ):改完配置常误以为立即生效,其实要等约1分钟事件才真正投递。
  4. @ 不触发:只有用@下拉框真正选中机器人才生成mention实体,直接敲@名称文本不触发事件。
  5. 群机器人被误移出:需API重建验证群(已用oc_a1c5...群完成)。

四、生产化两件必做事

长连接让本机跑通很容易,但生产第一天就要补两块——别和"外部攻击重放"混为一谈(散点文04专门讲):

// 跨实例幂等(Redis SETNX带TTL)Stringkey="event_id:"+event.getEventId();if(redis.setnx(key,"1",Duration.ofMinutes(5))){handle(event);// 同一event_id5分钟内重复投递直接丢弃}
  • event_id幂等:飞书在故障重投、重连补推时会重复发同一event_id,这是平台自身行为,不是攻击。必须按event_id去重,否则一条@会触发两次工具调用。重连后飞书会按断连时间窗口自动补推断线期间的事件,客户端无需人工补数,只要守住event_id去重即可——这也说明幂等为什么第一天就要做。
  • 多实例分发:一实例一条 WS、事件只进一个实例;多实例需跨实例共享去重(Redis 分发/发布订阅)。事件落到哪个实例:各实例各开一条 WS 接住全量事件,按chat_id一致性哈希把同一会话固定到同一实例(会话状态亲和),其余实例靠 Redis 全局去重防重复触发;或轮询分发(代价是InMemoryContextStore改 Redis 共享)。注意这与InMemoryContextStore(会话状态共享)是两个不同问题——前者是事件去重,后者是会话状态共享,别混。

长连接把飞书接入成本降到最低(5分钟起第1层,半天内第3层),是飞书官方推荐路线。但落到生产,得评估多实例分发与event_id幂等——这是平台自身重投,不是外部攻击重放(防御思路见散点文04)。


同专题推荐

本文是「飞书对接」小专题的第1篇,共5篇:

    1. 飞书长连接事件订阅实战:本机 5 分钟跑通,生产要补两块(← 当前这篇)
    1. 飞书卡片消息构建实战:从文本到可交互富卡片(链接待补)
    1. 飞书用户身份与多租户数据隔离:店长只看自己门店(链接待补)
    1. 飞书事件安全:签名校验与消息加解密(链接待补)
    1. 钉钉接入实战与平台横向差距(链接待补)

相关阅读

  • 《MCP实战手记系列(十一):MCP接飞书,从机器人到事件订阅的三层深度接入》
  • 《MCP实战手记系列(九):生产化MCP Server的6层安全防护》(身份透传底座)
  • 《MCP实战手记系列(十):MCP Server高可用实战》(6工具复用 StoreService)
  • 配套代码:https://gitee.com/ethanliang2016/mcp-in-action(模块11-feishu,tagv11)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询