NEW

免费试用已开放

立即开始

API 网关 · 长连接

企微开放平台和网关路线怎么配合

更新于 2026-08-169 分钟

混合架构翻车,很少是因为选错了路线,多半是因为两条路线都接上了,却没人说得清某类数据以哪一条为准。企微开放平台交付的是一个被企业授权的应用,网关式接入交付的是一个被托管的账号实例 —— 它们本来就不在同一层解决问题,并排接进系统不难,难的是划归属。归属划错还有个特点:联调期一定发现不了,因为那时候只有一个人在操作,时序天然是串行的。这篇给四道判断题、三条落地约束和一条灰度节奏,网关一侧按 wecomapi 的接入方式来写。

先承认两条线的动作主体不同

开放平台上的每一个动作,都以企业和应用的身份发生,能做什么由管理员勾选的权限项决定,边界是授权给出来的。网关那侧的动作以被托管的那个账号的身份发生,边界由登录态和平台的能力覆盖决定。同一件事从两条链路发出去,在接收方眼里根本不是同一件事。

这个差别决定了切分只能按主体切,不能按接口切。按接口切 —— 哪边接口顺手就用哪边 —— 的结果几乎必然是同一类数据被两条链路写入。客户备注是最典型的例子:官方那侧改一次,你的系统改一次,谁覆盖谁完全取决于时序,而时序在只有一个人联调的时候是看不出来的。

每接一个能力先问一句「这件事在企业微信里是以谁的身份发生的」。答不上来,说明它的业务归属还没想清楚,这时候接哪条都是错的。

四道判断题,按顺序问

顺序不能反。前一道能定下来的,就别动用后一道 —— 反过来用会得到一个看着很精细、实际没人维护得住的划分。

第一题:这件事以谁的身份发生

按主体切的那条线站内讲网关与开放平台六维对照的那篇已经给过,这里直接拿来用:以组织身份发生的事走开放平台,以成员对外触达身份发生的事走网关。这一题能分掉八成能力域,真正需要这篇展开的是剩下那两成 —— 后面三题都是为它们准备的。

第二题:这类数据的真相源在哪一侧

组织架构的真相源永远在企业微信侧,你库里那份只能是缓存。任何「在自己系统里改一下部门」的设计都迟早会和一次后台变更撞上。反过来,跟进记录、意向阶段、会话摘要的真相源在你自己的库,企业微信侧只是投影。真相源决定同步方向,同步方向决定冲突时谁赢 —— 这两句要写进设计文档,不是写进注释。

第三题:秒级反应,还是分钟级对账

对外会话这类强时效场景,用 wecomapi 的事件回调驱动,收到先快速 ACK 再异步处理;通讯录变更、群成员对齐这类定时拉取对账就够。别为了「实时」把所有能力都接成事件 —— 事件越多,幂等、乱序和重复投递的处理面越大,而这部分成本是隐性的,写完代码那天看不出来。也别反过来把强时效场景做成轮询,那是拿延迟换省事。

第四题:它失效的时候,是授权没了还是登录态没了

开放平台那侧的能力随企业授权变化,管理员一撤权就没了,而且通常没人通知你;网关那侧随账号登录态变化,账号掉线就没了,但状态是可观测的。两种失效的检测方式、告警对象和降级动作完全不同。把它们塞进同一个健康检查,你会得到一个永远说不清为什么变红的面板。

四道题走完仍然定不了归属的能力是存在的,最典型的是群 —— 内部项目群和客户外部群在业务上是两种东西,接口层面却容易被当成一类。这种时候不要发明第五道题,直接挑一个属性做硬判据,比如群里有没有外部成员。判据必须可枚举、可查询、不依赖人工填写,否则它迟早会被填错,而归属错误比归属模糊更难查。

把归属写成代码能检查的东西

判断题的结论写在文档里没有约束力,必须落成代码里能被违反、能被发现的东西。三条约束,缺一条混合架构就会慢慢烂掉。

唯一写者。每类数据只有一条链路能写,另一条只读。归属要落成一份配置表,而不是口头共识 —— 半年后加进来的人不会知道客户备注该由哪条链路负责。再狠一点的做法是在数据访问层直接拦:非写者链路调用写方法时抛异常,让违反在测试环境就炸出来,而不是等对账时才发现两侧互相覆盖。

单一事件入口。两侧的事件在入口就归一化成内部事件,业务代码永远不需要知道这条事件来自哪一侧。这条的收益不在优雅,在于来源判断一旦渗进业务层,之后任何一侧的调整都会退化成全仓库搜索替换。入口层可以按侧分开部署、分开限流,但出口只能有一种事件类型。

内部主键。同一个客户在两侧有两个外部标识,而且不保证能互相换算,别指望有一个字段能把它们对上。业务表只存自己的内部主键,外部标识全部退到一张映射表里,作为「某条链路上的某个身份」存在。第一周建这层的成本接近于零,等两侧都有半年数据了再补,就是一次带业务停机的对齐工程。

示意:归属表让越界写入在测试环境就失败typescript
// 示意代码,只表达约束的位置,不代表任一侧的真实字段与签名

type Lane = "official" | "gateway";

// 一类数据只能有一个写者,读者不限
const OWNER: Record<string, Lane> = {
  "org.department": "official",  // 真相源在企业微信侧
  "customer.note":  "gateway",   // 以成员对外身份发生的动作
  "customer.stage": "gateway",
};

export function assertWriter(domain: string, lane: Lane) {
  if (OWNER[domain] !== lane) throw new Error(`${lane} 不是 ${domain} 的写者`);
}

// 网关侧出向:POST https://manager.wecomapi.com/message/sendText
// 两侧回调都先快速 ACK,再把归一化后的内部事件投进同一条队列

归一化之后建议保留一个只用于排障的来源标记,但禁止业务分支读它。这条靠代码评审守,不靠自觉 —— 它一旦被业务逻辑消费,第二条约束就名存实亡了。

灰度:影子读、按域切、按域回退

混合架构的上线风险不在功能,在数据。功能坏了当场就知道,数据错了要等对账的时候才知道,而那时候错的已经不是一条记录。

  1. 1影子读:新链路只读不写,把它拿到的数据和旧链路比对,跑满一个完整业务周期。这一步暴露的不是 bug,是覆盖差异 —— 某类事件旧链路有、新链路没有,或者反过来。
  2. 2按能力域单写切换:一次只切一个域,切完观察,再切下一个。全量切换省下的那点时间,会在第一次回滚时连本带利还回去。
  3. 3回退开关的粒度必须是能力域,不能是全局。真实故障通常只压在一两个能力上,全局开关只给你「全回退或不回退」两个选项,两个都不是你想要的。

影子期具体怎么跑:用 wecomapi 的事件回调把网关侧事件全量收下来落库,但不让它产生任何副作用,然后逐日比对两侧的事件量、类型分布和到达时延。这比对着两份文档逐条核能力有效得多 —— 文档告诉你「支持」,影子数据告诉你「在你的场景里实际收到了什么」。

影子期的长度按业务周期定,不按天数定。有月结、有月度活动的业务,一周的影子数据说明不了问题,因为最容易出覆盖差异的恰恰是那些一个月才发生一次的事件。这段时间是整条上线路径里唯一可以从容犯错的窗口,压缩它省下的是排期,赔进去的是一次带数据修复的回滚。

什么时候不该混

混合是有固定成本的:两套监控口径、两套错误语义、两套凭证与轮换流程、两份合规材料。这笔成本按月发生,而混合带来的收益经常是一次性的。折算下来抵不过三个月的固定成本,就别做。

  1. 1只缺一两个边缘能力,而且有能接受的替代路径 —— 用替代路径,别为它引入第二条链路。
  2. 2团队投入不足三人。双链路的监控、告警和值班是持续负担,人不够时它会先烂在「告警没人看」这一环。
  3. 3合规评审只批了一条链路。这条没有商量余地,先把评审过了再谈架构。
  4. 4交付形态是要上架、被其他企业安装。主干必须是开放平台,网关只能作为增量补在授权拿不到的那几块上,不要做成对等的两条。

关于取舍还有一句话:混合架构的价值不是「两边的能力加起来」,而是「每个能力都有唯一归属,且这个归属是按主体推导出来的,不是按当时哪个接口好调决定的」。前者能撑三年,后者撑不过第二次需求变更。判断自己属于哪一种有个很快的办法:随便挑三个能力,问三个不同的人它归哪条链路,答案不一致就说明你现在只是接了两套接口,还没有混合架构。

本文讲的是归属原则与落地顺序,不涉及任一侧的接口定义。两侧的精确字段、权限项与端点以各自的线上文档为准,网关一侧以 wecomapi 文档为准。

常见问题

通讯录同步能不能走网关那条?
不建议。组织架构的真相源在企业微信侧,这类数据用授权关系明确的官方链路拿最省心,出问题时责任边界也清楚。两条链路各拿一份部门树,最后一定会出现两份对不上的口径,而你没有第三方仲裁。网关那条留给对外触达与会话,边界清楚得多。
两条链路的回调要不要分成两个地址?
要分。分开之后网络层的问题能一眼定位到是哪一侧,也方便按侧独立限流、独立灰度和独立停摆。归一化在入口之后做,业务层依然只看到一种内部事件,所以分地址不会破坏统一性 —— 它破坏的只是「一个 handler 打天下」的错觉。
已经全量用开放平台了,补网关从哪块能力开始?
从「授权始终拿不到、业务上又非要不可」的那一块开始,通常落在对外会话和外部群上。先用 wecomapi 把这一个能力域的闭环跑通、观察一个完整业务周期,再决定要不要扩到第二个域。一上来就规划全量迁移,多数会停在身份映射那一步。

准备好动手了?

精确字段、鉴权与端点以线上文档为准;可在控制台创建密钥后联调。

相关文章