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

TypeError: 循环结构转JSON错误:Socket.IO Client+RTK Query问题求助

解决RTK Query传入Socket实例时的循环结构序列化错误

错误原因

RTK Query在处理endpoint参数时,会对参数进行序列化(用于生成缓存键、日志记录等场景)。而Socket.IO客户端实例内部存在循环引用(比如socket实例与manager互相引用),直接将其作为参数传入endpoint会触发JSON序列化失败的错误。

解决方法

1. 将Socket实例全局注入到API切片(推荐)

不要在调用endpoint时传递Socket实例,而是在创建RTK Query的API切片时,通过extra参数注入Socket,在queryFn中直接使用:

// 创建API切片
const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/' }),
  endpoints: (builder) => ({
    sendSocketMessage: builder.mutation({
      queryFn: async (message, { extra }) => {
        // 从extra中获取预先注入的Socket实例
        const socket = extra.socket;
        try {
          await socket.emit('send-message', message);
          return { data: '发送成功' };
        } catch (err) {
          return { error: { status: 'CUSTOM_ERROR', error: err.message } };
        }
      },
    }),
  }),
});

// 配置Store时注入Socket实例
const socket = io();
const store = configureStore({
  reducer: {
    [api.reducerPath]: api.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      thunk: {
        extraArgument: { socket },
      },
    }).concat(api.middleware),
});

// 调用endpoint时仅传递业务数据
dispatch(sendSocketMessage({ content: 'Hello Socket' }));

2. 封装Socket操作函数

提前封装好Socket的业务操作,在endpoint的queryFn中直接调用封装函数,避免直接传递Socket实例:

// 封装Socket工具函数
const socket = io();
export const socketService = {
  sendMessage: (message) => {
    return new Promise((resolve, reject) => {
      socket.emit('send-message', message, (response) => {
        response.success ? resolve(response) : reject(new Error(response.error));
      });
    });
  },
};

// 在API切片中调用封装函数
const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/' }),
  endpoints: (builder) => ({
    sendSocketMessage: builder.mutation({
      queryFn: async (message) => {
        try {
          const data = await socketService.sendMessage(message);
          return { data };
        } catch (err) {
          return { error: { status: 'CUSTOM_ERROR', error: err.message } };
        }
      },
    }),
  }),
});

3. 自定义参数序列化逻辑(不推荐)

如果必须传递Socket实例,可通过serializeQueryArgs跳过对Socket的序列化,但可能影响缓存键的正确性,需谨慎使用:

const api = createApi({
  baseQuery: fetchBaseQuery({ baseUrl: '/' }),
  // 自定义序列化逻辑,排除Socket实例
  serializeQueryArgs: ({ queryArgs }) => {
    const { socket, ...validArgs } = queryArgs;
    return JSON.stringify(validArgs);
  },
  endpoints: (builder) => ({
    sendSocketMessage: builder.mutation({
      queryFn: async ({ socket, message }) => {
        try {
          await socket.emit('send-message', message);
          return { data: '发送成功' };
        } catch (err) {
          return { error: { status: 'CUSTOM_ERROR', error: err.message } };
        }
      },
    }),
  }),
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 07:01:07