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

Apollo GraphQL Server订阅:如何仅发送客户端关注的变更数据?

Apollo Server 订阅仅推送变更字段方案

要实现只在客户端关注的字段发生变化时才推送更新,且不用手动处理字段解析或获取订阅信息,可以通过以下方式实现:

  • 利用Apollo Server插件拦截订阅结果
    Apollo Server的插件系统提供了订阅生命周期钩子,其中didResolveSubscription可以在解析出要发送给客户端的结果后、实际推送前介入。你可以在这个钩子中,为每个WebSocket连接维护上次发送结果的缓存,对比当前结果与缓存值,只有当两者不同时才允许推送。

    示例代码如下:

    const { ApolloServer } = require('@apollo/server');
    const { isEqual } = require('lodash'); // 用深对比替代JSON.stringify,更可靠
    
    const server = new ApolloServer({
      typeDefs,
      resolvers,
      plugins: [
        {
          async didResolveSubscription(context, payload) {
            // 从连接上下文获取缓存的上次结果
            const cache = context.connectionContext.cache;
            const connectionId = context.connectionContext.connectionId;
            const lastPayload = cache.get(connectionId);
    
            // 深对比当前结果与上次结果
            if (lastPayload && isEqual(payload, lastPayload)) {
              // 无变化则返回null,终止推送
              return null;
            }
    
            // 更新缓存为当前结果
            cache.set(connectionId, payload);
            return payload;
          },
        },
      ],
      context: ({ connection }) => {
        // 为每个WebSocket连接初始化专属缓存
        if (connection) {
          return {
            connectionContext: {
              connectionId: connection.id, // 用Apollo自动生成的连接ID标识
              cache: new Map(),
            },
          };
        }
        return {};
      },
    });
    
  • 自定义订阅执行流程
    如果你需要更灵活的控制,可以自定义订阅的执行逻辑。在订阅解析器中,每次生成数据源的更新后,先让Apollo根据客户端的订阅字段解析出最终响应,再与该客户端的历史响应对比。这种方式依赖Apollo的info对象完成字段筛选,你只需要负责对比结果。

    示例代码如下:

    const resolvers = {
      Subscription: {
        dataUpdate: {
          async subscribe(parent, args, context, info) {
            // 假设你的数据源是一个AsyncIterator
            const iterator = yourDataSource.getUpdates();
            return {
              async next() {
                const { value, done } = await iterator.next();
                if (done) return { done };
    
                // 让Apollo根据客户端的订阅字段解析结果
                const resolvedValue = await info.schema.execute({
                  schema: info.schema,
                  document: info.document,
                  rootValue: value,
                  contextValue: context,
                  variableValues: info.variableValues,
                  operationName: info.operationName,
                });
    
                // 对比缓存的上次结果
                const lastValue = context.connectionContext.cache.get(context.connectionContext.connectionId);
                if (lastValue && isEqual(resolvedValue.data, lastValue)) {
                  // 无变化则跳过本次,继续获取下一个更新
                  return this.next();
                }
    
                context.connectionContext.cache.set(context.connectionContext.connectionId, resolvedValue.data);
                return { value: resolvedValue.data, done: false };
              },
              async return() {
                return iterator.return();
              },
              async throw(error) {
                return iterator.throw(error);
              },
              [Symbol.asyncIterator]() {
                return this;
              },
            };
          },
        },
      },
    };
    

这两种方案的核心都是让Apollo完成客户端订阅字段的自动筛选,你只需要对比最终要发送给客户端的结果是否与上次一致,避免重复实现字段解析逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 17:06:57