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

gRPC-web拦截器中止调用后如何返回缓存并触发回调?

问题分析

你当前的实现有两个核心问题:

  1. 调用stream.cancel()会触发gRPC-web的错误事件,导致client.hello的回调收到错误参数,而非预期的缓存结果;
  2. 你仍然通过invoker(request)发起了真实请求,后续的cancel只是终止请求,无法让回调正常获取缓存数据。

解决方案

正确的思路是:当存在缓存时,跳过真实请求的发起,直接返回一个模拟的gRPC Stream对象,主动触发data和end事件,让客户端回调正常获取缓存结果。

修改后的拦截器代码:

const StreamInterceptor = function () {};

StreamInterceptor.prototype.intercept = function (request, invoker) {
  // 模拟缓存判断,实际场景替换为你的缓存逻辑
  const cachedResponse = { message: 'world' };
  
  if (cachedResponse) {
    // 返回模拟的Stream,不发起真实请求
    const MockStream = function () {
      this.listeners = {};
    };

    // 实现gRPC Stream核心方法
    MockStream.prototype.on = function (eventType, callback) {
      if (!this.listeners[eventType]) {
        this.listeners[eventType] = [];
      }
      this.listeners[eventType].push(callback);

      // 监听data事件时,立即返回缓存并触发end
      if (eventType === 'data') {
        process.nextTick(() => callback(cachedResponse));
        process.nextTick(() => this.emit('end'));
      }
      return this;
    };

    MockStream.prototype.emit = function (eventType) {
      if (this.listeners[eventType]) {
        this.listeners[eventType].forEach(cb => cb());
      }
    };

    // 空实现cancel方法,避免调用报错
    MockStream.prototype.cancel = function () {};

    return new MockStream();
  }

  // 无缓存时,正常发起真实请求
  return invoker(request);
};

客户端调用代码保持不变:

const client = new ServiceClient('http://localhost:8080', null, {
  streamInterceptors: [new StreamInterceptor()],
});
client.hello(message, {}, (err, res) => {
  console.log(res); // 现在会输出 { message: 'world' }
});

关键说明

  • 当存在缓存时,直接返回模拟Stream,彻底跳过真实请求的发起,无需后续cancel操作;
  • 模拟Stream实现了gRPC-web要求的on、emit、cancel方法,确保客户端调用逻辑完全兼容;
  • 通过process.nextTick延迟触发事件,符合JS异步回调的执行逻辑,避免同步执行导致的时序问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 15:52:33