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

如何在RTK Query外部的请求中正确传递凭据?

问题:RTK Query GraphQL请求正常携带Cookie,但独立fetch请求无法传递凭据

我们使用RTK Query结合GraphQL basequery,在basequery中设置credentials: "include"后,所有GraphQL请求都能正常获取并携带Cookie,相关代码如下:

export const api = createApi({
  baseQuery: baseQueryWithErrorHandlingGQL,
  refetchOnMountOrArgChange: true,
  refetchOnReconnect: true,
  tagTypes: ["Submission", "Poll", "Logout", "Enroll", "Log"],    
  endpoints: () => ({}),
});

export const rawBaseQueryGQL: BaseQueryFn<
  IGQLBaseQuery,
  unknown,
  Partial<ClientError & { errorCode: number }>
> = async ({ document, variables }, api, extraOptions) => {
  const client = new GraphQLClient(
    process.env.REACT_APP_GRAPHQL_URL ||
      "https://www.example.com/graphql",
    {
      credentials: "include",
    }
  );

  client.setHeader("Accept", "application/json");
  client.setHeader("Content-Type", "application/json");
  client.setHeader("Access-Control-Allow-Credentials", "true");

  const query = graphqlRequestBaseQuery<
    Partial<ClientError & { errorCode: number }>
  >({
    client,

    customErrors: ({ name, stack, response }) => {
      const { errorMessage = "", errorCode = 500 } = response?.errors?.length
        ? response?.errors[0]?.extensions
        : {};

      return {
        name,
        message: errorMessage,
        errorCode,
        stack,
      };
    },
  });

  return query({ document, variables }, api, extraOptions);
};

但当我们在RTK Query之外,用fetch请求一个简单的上传端点时,凭据并未被传递,请求代码如下:

const response = await fetch(`${Globals.URLS.BASE_URL}/upload`, {
                method: 'POST',
                credentials: 'include',
                headers: {
                    'Content-Type': 'multipart/form-data',
                    "Accept": "application/json",
                },
                body: formData,
            });

请问如何获取Cookie并将其传递给该新端点?我们的另一个备选方案是在GraphQL中创建一个全新的端点。


解决方案

1. 排查基础问题

  • 确认同源性:检查Globals.URLS.BASE_URL是否和GraphQL请求的域名完全一致(包括协议http/https、域名、端口)。Cookie的同源策略要求严格匹配,跨域场景下即使设置credentials: "include",也需要后端配置对应CORS规则才能携带。
  • 检查Cookie属性:查看Cookie的SameSite、Secure属性:
    • 跨域场景下,SameSite必须设为None,同时搭配Secure属性(仅HTTPS环境有效);
    • 同域场景下,SameSite设为Lax或Strict均可,确保没有其他限制(比如HttpOnly不影响前端携带,但如果是HttpOnly的Cookie,document.cookie无法读取,只能靠浏览器自动携带)。

2. 手动携带Cookie(同域场景)

如果是同域请求,可直接通过document.cookie获取所有Cookie,手动添加到fetch请求头中:

const cookies = document.cookie;
const response = await fetch(`${Globals.URLS.BASE_URL}/upload`, {
    method: 'POST',
    credentials: 'include',
    headers: {
        'Accept': "application/json",
        'Cookie': cookies, // 手动注入Cookie
    },
    body: formData,
});

注意:不要手动设置Content-Type: multipart/form-data,当body为FormData时,浏览器会自动生成包含boundary的正确请求头,手动设置反而会导致请求异常。

3. 跨域场景处理

如果是跨域请求,需要后端配合配置CORS响应头:

Access-Control-Allow-Origin: 你的前端域名(不能为*)
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Cookie, Accept

同时确保Cookie的SameSite=None和Secure属性配置正确。

4. 复用RTK Query的配置(推荐)

将上传请求封装成RTK Query的endpoint,自动继承basequery的凭据配置,无需单独处理Cookie:

// 扩展api的endpoints
export const api = createApi({
  baseQuery: baseQueryWithErrorHandlingGQL,
  refetchOnMountOrArgChange: true,
  refetchOnReconnect: true,
  tagTypes: ["Submission", "Poll", "Logout", "Enroll", "Log"],    
  endpoints: (builder) => ({
    uploadFile: builder.mutation({
      // 如果上传是REST端点,需要使用支持REST的baseQuery,可单独创建一个通用REST baseQuery
      query: (formData) => ({
        url: `${Globals.URLS.BASE_URL}/upload`,
        method: 'POST',
        body: formData,
        credentials: 'include',
        headers: {
          Accept: "application/json",
        },
      }),
    }),
  }),
});

// 组件中使用该端点
const [uploadFile] = useUploadFileMutation();
const uploadResult = await uploadFile(formData);

如果原baseQuery仅处理GraphQL,可新建一个通用的REST baseQuery,统一管理凭据配置,避免重复代码。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 12:43:19