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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 04:14:52