You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js Redis NRP订阅回调未执行:API网关收不到返回消息

排查Redis Pub/Sub(NRP库)订阅回调不触发的问题

我来帮你一步步拆解这个问题——你已经打通了API网关到通知服务的发布链路,Redis也显示网关已经订阅了目标频道,但就是收不到返回消息的回调,大概率是几个细节没处理到位,咱们逐个排查:

1. 先确认:回调到底有没有被触发?

你现在的回调里加了data.rmid == data.mid的判断,很可能消息已经收到了,但因为ID不匹配没走到resolve逻辑,导致你误以为回调没触发。

先给订阅回调加个全局日志,把所有收到的消息都打出来:

Subscribe(pattern, callback) {
  console.log('Im gonna subscribe to', pattern);
  nrp.on(pattern, (data, channel) => {
    // 新增这行,不管ID匹配与否,先打印所有收到的消息
    console.log('[DEBUG] 收到频道消息:', channel, data);
    console.log('subd on ' + pattern);
    return callback(data, channel);
  });
}

同时在API网关的订阅回调里也加日志:

this.sub.Subscribe(subchannel, (data, channel) => {
  console.log('[API网关] 收到回调数据:', data);
  let body = data.body;
  let message = body.message;
  if(data.rmid == data.mid){
    // ... 原有逻辑
  }
});

跑一遍登录流程,看控制台有没有打印这些日志——如果有,说明回调已经触发,问题出在ID匹配逻辑上;如果没有,再往下排查。

2. 检查NRP订阅方法的实现是否符合库的规范

从你的代码看,你直接用nrp.on(pattern, ...)来绑定订阅回调,但很多Redis Pub/Sub库中,on是用来监听全局事件(比如message),而不是直接订阅频道。如果NRP的API要求先调用subscribe方法再监听消息,那你的写法就错了。

比如NRP的正确订阅方式可能是这样:

Subscribe(pattern, callback) {
  console.log('Im gonna subscribe to', pattern);
  // 先调用订阅API,订阅目标频道
  nrp.subscribe(pattern);
  // 监听全局的message事件,判断频道是否匹配
  nrp.on('message', (channel, data) => {
    if (channel === pattern) {
      console.log('subd on ' + pattern);
      callback(data, channel);
    }
  });
}

你可以对照NRP的官方文档确认API用法——如果当前的Subscribe方法没有主动调用订阅接口,那网关其实只是绑定了事件,并没有真正订阅频道(虽然Redis客户端显示已订阅,但可能是其他逻辑导致的)。

3. 验证消息ID的匹配逻辑

你的回调逻辑依赖data.rmid == data.mid,但要确保:

  • API网关发布消息时,有没有生成唯一的mid并传递给通知服务?比如发布时要带上这个ID:
    // 生成唯一消息ID
    const mid = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
    const sent = this.sub.publish(pubchannel, {
      mid: mid, // 把mid放到根字段,方便通知服务获取
      body: {
        param: params,
        message: '',
      }
    });
    
  • 通知服务处理完登录后,有没有把收到的mid作为rmid返回?比如通知服务发布返回消息时:
    // 假设收到的消息是reqData
    nrp.publish(subchannel, {
      rmid: reqData.mid, // 用网关发来的mid作为rmid返回
      body: {
        message: '登录成功'
      }
    });
    

如果这两个ID不对应,你的回调里的逻辑就永远不会执行。

4. 检查退订和关闭连接的时机

你在回调里直接调用sub.unSubscribe((nrp)=>{ nrp.quit(); resolve(message); });,这个写法可能有问题:

  • 先确保unSubscribe方法能正确退订指定频道,而不是退订所有频道;
  • 建议先resolve结果,再执行退订和关闭连接的操作,避免因为连接提前关闭导致resolve逻辑没完成:
    if(data.rmid == data.mid){
      // 先返回结果
      resolve(message);
      // 再退订频道并关闭连接
      sub.unSubscribe(subchannel);
      nrp.quit();
    }
    

最后再确认一个小细节

确保API网关用来发布和订阅的是同一个NRP实例——如果发布用了一个实例,订阅用了另一个,哪怕Redis显示订阅了频道,不同实例的连接也收不到消息。


内容的提问来源于stack exchange,提问作者Gisrou8

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:20:55