gRPC-web拦截器中止调用后如何返回缓存并触发回调?
问题分析
你当前的实现有两个核心问题:
- 调用
stream.cancel()会触发gRPC-web的错误事件,导致client.hello的回调收到错误参数,而非预期的缓存结果; - 你仍然通过
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
相关产品推荐
相关产品推荐

