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

Redux Toolkit Query GraphQL订阅无法运行,请求技术帮助

解决RTK Query + GraphQL订阅的subscriptions are not supported over HTTP错误

问题根源

你用builder.query定义订阅时,RTK Query会默认通过HTTP POST请求发送这个GraphQL Subscription操作,但GraphQL订阅只能通过WebSocket协议处理,因此服务器返回错误提示。

修复方案

1. 拆分初始数据查询与订阅逻辑

用普通的GraphQL Query通过HTTP获取初始数据,再在onCacheEntryAdded中建立WebSocket连接处理订阅更新,避免RTK Query发送HTTP请求执行Subscription操作。

2. 修改后的代码示例

userStatus: builder.query<
  UserStatusQueryResult, // 替换为你的普通查询返回类型
  { event_id: string; user_id: string }
>({
  // 用普通Query获取初始数据,而非Subscription
  query: ({ event_id, user_id }) => ({
    document: gql`
      query GetUserStatus($event_id: uuid!, $user_id: String!) {
        eetschema_event_by_pk(id: $event_id) {
          event_attendees(where: { user_id: { _eq: $user_id } }) {
            status
            event_id
            user_id
          }
        }
      }
    `,
    variables: { event_id, user_id },
  }),
  async onCacheEntryAdded(
    arg,
    { updateCachedData, cacheDataLoaded, cacheEntryRemoved }
  ) {
    // 连接GraphQL WebSocket端点(根据你的服务器配置调整路径)
    const ws = new WebSocket("ws://localhost:8080/graphql");
    let resolveConnection: () => void;
    const connectionReady = new Promise<void>(res => resolveConnection = res);

    // 连接建立后发送订阅请求
    ws.onopen = () => {
      ws.send(JSON.stringify({
        type: "start",
        id: "user-status-sub-1",
        payload: {
          query: `
            subscription UserStatusSubscription($event_id: uuid!, $user_id: String!) {
              eetschema_event_by_pk(id: $event_id) {
                event_attendees(where: { user_id: { _eq: $user_id } }) {
                  status
                  event_id
                  user_id
                }
              }
            }
          `,
          variables: arg
        }
      }));
      resolveConnection();
    };

    try {
      // 等待初始数据缓存完成 + WebSocket连接就绪
      await cacheDataLoaded;
      await connectionReady;

      const handleMessage = (event: MessageEvent) => {
        const message = JSON.parse(event.data);
        // 处理服务器返回的订阅数据(格式根据你的服务器调整)
        if (message.type === "data" && message.id === "user-status-sub-1") {
          updateCachedData((draft) => {
            // 正确修改Immer draft,不能直接赋值
            draft.eetschema_event_by_pk = message.payload.data.eetschema_event_by_pk;
          });
        }
      };

      ws.addEventListener("message", handleMessage);
    } catch {
      // 忽略缓存提前销毁的异常
    }

    // 缓存订阅结束时清理WebSocket连接
    await cacheEntryRemoved;
    ws.send(JSON.stringify({ type: "stop", id: "user-status-sub-1" }));
    ws.close();
  },
}),

3. 额外注意事项

  • 确认你的GraphQL服务器已配置WebSocket订阅支持(比如使用graphql-ws或subscriptions-transport-ws库)。
  • WebSocket消息格式需匹配服务器要求(示例使用的是graphql-ws的标准格式,若你用的是旧版subscriptions-transport-ws,格式会有差异)。
  • 更新缓存时必须修改Immer draft的属性,不能直接替换整个draft对象,否则RTK Query无法跟踪缓存变更。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 22:19:22