如何在RTK Query的createApi prepareHeaders中获取跨API鉴权Token?
解决RTK Query中WeatherKit API获取自研接口Token的问题
你遇到的核心问题是RTK Query的React Hooks(如useGetWeatherKitTokenQuery)只能在React组件或自定义Hook的上下文里调用,不能直接在createApi的配置函数(比如prepareHeaders)中使用,这违反了React Hook的调用规则。以下是几种可行的解决方案:
方案一:将WeatherKit请求整合到自研API的Endpoint中
把WeatherKit的请求作为自研API的一个新Endpoint,先调用获取Token的接口,再发起WeatherKit请求,逻辑完全内聚。
修改自研API代码:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const generalApi = createApi({ reducerPath: 'api', tagTypes: ['settings'], baseQuery: fetchBaseQuery({ baseUrl: 'https://api.myapp.com/v1/', prepareHeaders: (headers, { getState }) => { const token = getState().session.token; if (token) { headers.set('authorization', `Bearer ${token}`); } return headers; } }), endpoints: (builder) => ({ getWeatherKitToken: builder.query({ query: () => 'getWeatherKitToken', providesTags: ['settings'] }), login: builder.mutation({ query: (body) => ({ url: 'login', method: 'POST', body: body }), invalidatesTags: ['settings'] }), // 添加WeatherKit可用性查询接口 getWeatherKitAvailability: builder.query({ async queryFn({ lat, lon }, _queryApi, _extraOptions, baseQuery) { // 先调用自研接口获取WeatherKit Token const tokenRes = await baseQuery('getWeatherKitToken'); if (tokenRes.error) return { error: tokenRes.error }; const weatherKitToken = tokenRes.data; // 发起WeatherKit请求 const weatherRes = await fetch( `https://weatherkit.apple.com/api/v1/availability/${lat}/${lon}`, { headers: { 'authorization': `Bearer ${weatherKitToken}` } } ); if (!weatherRes.ok) { return { error: { status: weatherRes.status, data: await weatherRes.json() } }; } return { data: await weatherRes.json() }; } }) }), }); export const { useGetWeatherKitTokenQuery, useLoginMutation, useGetWeatherKitAvailabilityQuery // 导出新的查询Hook } = generalApi;
方案二:将WeatherKit Token存入Redux Store,在WeatherKit API中获取
通过Redux Store共享Token,在WeatherKit的prepareHeaders中直接从Store读取。
步骤1:创建保存WeatherKit Token的Slice
import { createSlice } from '@reduxjs/toolkit'; const weatherKitSlice = createSlice({ name: 'weatherKit', initialState: { token: null }, reducers: { setWeatherKitToken: (state, action) => { state.token = action.payload; } } }); export const { setWeatherKitToken } = weatherKitSlice.actions; export default weatherKitSlice.reducer;
记得将这个Slice添加到你的Redux Store配置中。
步骤2:修改自研API,获取Token后存入Store
// 在自研API的getWeatherKitToken接口中添加onQueryStarted getWeatherKitToken: builder.query({ query: () => 'getWeatherKitToken', providesTags: ['settings'], async onQueryStarted(_arg, { dispatch, queryFulfilled }) { const { data } = await queryFulfilled; dispatch(setWeatherKitToken(data)); // 将Token存入Store } }),
步骤3:在WeatherKit API的prepareHeaders中读取Token
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const weatherKitApi = createApi({ reducerPath: 'weatherKit', baseQuery: fetchBaseQuery({ baseUrl: 'https://weatherkit.apple.com/api/v1/', prepareHeaders: (headers, { getState }) => { const weatherKitToken = getState().weatherKit.token; if (weatherKitToken) { headers.set('authorization', `Bearer ${weatherKitToken}`); } return headers; } }), endpoints: (builder) => ({ availability: builder.query({ query: ({ lat, lon }) => `availability/${lat}/${lon}`, }) }) }); export const { useAvailabilityQuery } = weatherKitApi;
注意:使用此方案时,需确保调用WeatherKit接口前已成功获取并保存Token。可在组件中先调用useGetWeatherKitTokenQuery,等Token就绪后再调用useAvailabilityQuery。
方案三:用injectEndpoints将WeatherKit接口注入自研API
利用RTK Query的injectEndpoints能力,在自研API上下文里调用Token接口,无需修改原有API结构:
// 在自研API文件末尾添加 generalApi.injectEndpoints({ endpoints: (builder) => ({ weatherKitAvailability: builder.query({ async queryFn({ lat, lon }, queryApi) { // 调用自研API的getWeatherKitToken接口 const { data: token } = await queryApi.dispatch(generalApi.endpoints.getWeatherKitToken.initiate()); if (!token) { return { error: { status: 'CUSTOM_ERROR', data: '获取WeatherKit Token失败' } }; } // 发起WeatherKit请求 const response = await fetch( `https://weatherkit.apple.com/api/v1/availability/${lat}/${lon}`, { headers: { authorization: `Bearer ${token}` } } ); return { data: await response.json() }; } }) }) }); export const { useWeatherKitAvailabilityQuery } = generalApi;
各方案对比
- 方案一:逻辑集中,无需额外Store管理,适合简单场景。
- 方案二:API职责分离清晰,适合复杂业务场景,需维护Token生命周期。
- 方案三:灵活度高,无需修改原有API结构,适合快速扩展。
内容的提问来源于stack exchange,提问作者Tim Nikischin
相关产品推荐
相关产品推荐

