如何在RTK Query外部的请求中正确传递凭据?
我们使用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
相关产品推荐
相关产品推荐

