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

Apollo Client上下文无请求头,Cookie认证失效问题排查

问题分析与修复方案

核心问题拆解

  1. authLink逻辑依赖无效的初始headers:你的authLink优先检查传入的headers?.authorization,但这是链路的第一个环节,初始请求不存在预设headers,导致该判断永远不生效,必然进入NO TOKEN分支。
  2. getCookie未适配SSR/客户端环境:Next.js中服务端无法访问document.cookie,必须从请求头的Cookie字段解析;若你的getCookie未区分环境,或用了不必要的异步实现,会导致token读取失败。
  3. SSR场景未传递请求上下文:使用NextSSRApolloClient时,SSR阶段需将包含Cookie的请求对象传递给链路,否则服务端无法获取Cookie中的token。

修复步骤

1. 修正authLink逻辑,移除无效判断

直接从Cookie获取token,无需依赖初始headers:

const authLink = setContext(async (_, { headers }) => {
  // 直接从Cookie读取token,跳过无效的existingToken检查
  const token = await getCookie(ACCESS_TOKEN_COOKIE_NAME);
  
  const authorization = token ? `Bearer ${token.value}` : undefined;

  return {
    headers: {
      ...headers,
      // token不存在时不传空字符串,避免覆盖默认headers
      ...(authorization && { authorization }),
    },
  };
});

2. 完善getCookie函数,适配双环境

修改getCookie,支持服务端传入request对象:

// cookies.js
export const getCookie = (name, req) => {
  // 服务端场景:从request的Cookie头解析
  if (req) {
    const cookieHeader = req.headers.cookie;
    if (!cookieHeader) return null;
    const cookies = cookieHeader.split(';').reduce((acc, cookie) => {
      const [key, value] = cookie.trim().split('=');
      acc[key] = decodeURIComponent(value);
      return acc;
    }, {});
    return cookies[name] ? { value: cookies[name] } : null;
  }
  // 客户端场景:从document.cookie解析
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return { value: decodeURIComponent(parts.pop().split(';').shift()) };
  return null;
};

3. 链路函数接收SSR请求上下文

让getApolloClientLink接收request参数,在SSR时传递给getCookie:

export const getApolloClientLink = (req) => { // 新增req参数
  const httpLink = new HttpLink({
    uri: `${apiBaseUrl}/graphql`,
    credentials: "same-origin",
  });

  const authLink = setContext(async (_, { headers }) => {
    // 传入req到getCookie,适配SSR场景
    const token = await getCookie(ACCESS_TOKEN_COOKIE_NAME, req);
    
    const authorization = token ? `Bearer ${token.value}` : undefined;

    return {
      headers: {
        ...headers,
        ...(authorization && { authorization }),
      },
    };
  });

  return authLink.concat(httpLink);
};

4. 注册Client时传递SSR上下文

修改registerApolloClient逻辑,将SSR的request传入链路:

export const { getClient } = registerApolloClient(
  (context) => { // context包含SSR的request对象
    return new NextSSRApolloClient({
      cache: new NextSSRInMemoryCache(),
      link: getApolloClientLink(context?.req), // 传入req
    });
  },
);

额外检查点

  • 确认ACCESS_TOKEN_COOKIE_NAME常量与实际Cookie名称完全一致
  • 客户端Cookie的path设置为/,确保在GraphQL接口路径下可被读取
  • 同域场景下credentials: "same-origin"配置正确,无需额外CORS设置

内容的提问来源于stack exchange,提问作者Pierre Olivier Tran

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:57:42