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

GraphQL Mutation在Playground正常但客户端代码运行报错

问题1:首次调用refreshTokens返回Cannot return null for non-nullable field Mutation.refreshTokens.的根因与修复

你的issueNewToken函数存在逻辑漏洞:当请求头中不存在rt字段时,函数既没有抛出错误也没有返回值,最终返回undefined,而GraphQL schema中定义了refreshTokens返回非空的Auth!类型,因此触发非空校验报错。
修复代码:

issueNewToken: async (req) => {
    try {
      const token = req.headers.rt;
      if (!token) {
        throw new AuthenticationError("Refresh token not provided.");
      }
      const decoded = await jwt.verify(token, jwtRefreshTokenSecret);
      let user = await User.findById(decoded.id);
      if (!user) {
        throw new AuthenticationError("No user found.");
      }
      let tokens = await authFunctions.issueToken(user);
      return { ...tokens, user };
    } catch (err) {
      throw new AuthenticationError("Invalid Refresh Token.");
    }
},

问题2:令牌刷新成功后后续请求未携带正确Header的修复点

你的Apollo链路逻辑存在4处明显问题:

    1. refreshTokens函数没有返回刷新后的令牌信息,导致then回调中拿到的refreshTokensResult为undefined
    1. 构造新请求头时未展开旧header对象,导致原有header被覆盖丢失
    1. 全局header链路只配置了rt字段,未携带业务请求需要的Authorization access token头
    1. 主业务用的Apollo Client实例未注册errorLink和headerLink,刷新逻辑和header注入逻辑未生效

分步修复代码:

1. 修复refreshTokens函数的返回值
const refreshTokens = async () => {
  const {
    data: { refreshTokens: res },
  } = await renewTokenApiClient.mutate({
    mutation: REFRESH_TOKENS,
  });
  localStorage.setItem("refreshtoken", res.refreshToken);
  localStorage.setItem("token", res.token);
  // 新增返回值供后续逻辑使用
  return res;
};
2. 修复headerLink逻辑,同时注入两个需要的头
const headerLink = setContext((_, { headers }) => {
  const refreshToken = localStorage.getItem("refreshtoken");
  const accessToken = localStorage.getItem("token");
  return {
    headers: {
      ...headers,
      rt: refreshToken || "",
      Authorization: accessToken ? `Bearer ${accessToken}` : "",
    },
  };
});
3. 修复errorLink中构造headers的逻辑
refreshTokens().then((refreshTokensResult) => {
  let headers = {
    // 展开旧header,不要直接写oldHeaders
    ...oldHeaders,
    Authorization: `Bearer ${refreshTokensResult.token}`,
    rt: refreshTokensResult.refreshToken,
  };
  operation.setContext({ headers });
})
4. 主Apollo Client实例注册完整链路

确保你全局使用的Apollo Client按顺序注册了所有链路:

const client = new ApolloClient({
  // 链路顺序:errorLink在前,然后是header注入,最后是http请求
  link: from([errorLink, headerLink, createHttpLink({ uri: "/graphql" })]),
  cache,
  credentials: "include",
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 20:06:03