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

如何通过自定义中间件在RTK Query发起前获取Token?

Redux中间件异步获取Token未等待完成导致RTK Query请求无Token问题

我要开发一个Redux中间件,在RTK Query发起动作时获取Token(后续会添加Token过期检查,当前仅做获取测试)。但从Azure获取Token是异步操作,中间件没有等待Token获取完成就继续执行,导致RTK Query发起数据请求时Token尚未准备就绪。我对Redux及中间件中的异步逻辑理解可能存在偏差。


authMiddleware.ts

export const authMiddleware: Middleware =
  ({ dispatch, getState }) => next => async (action: PayloadAction) => {
    // const store = getState() as RootState;
    console.log('Dispatching action:', action.type);
    logWithTime('Middleware: action is a function and started');

    if (action.type === 'apiInvoices/config/middlewareRegistered') {
      logWithTime(
        'middleware in action: apiInvoices/config/middlewareRegistered'
      );
      let token: string | void = '';
      console.log('Action in if: ', action.type)
      const tokenProvider: AadTokenProvider = await getAadTokenProvider();

      if (tokenProvider) {
        logWithTime('Token provider set');
      }

      // check if tokenProvider is not null
      if (tokenProvider) {
        console.log('Token provider:', tokenProvider);
      } else {
        console.log('Token provider is null')
      }

      // fetch token, wait till token is fetched and then set
      // token in store then return next action
      token = await tokenProvider.getToken(
        '6cbc9b1e-901d-4a99-a947-ae36ffe3ac38'
      )
        .then(token => {
          setToken({ endpoint: 'getInvoiceByID', token: token })
        })
        .then(() => {
          logWithTime('Token fetched and set in store');
          next(action)
        });
    }
  };

store.ts

import { configureStore } from '@reduxjs/toolkit';
import { tokenReducer } from '../slices/tokenSlice';
import { apiInvoices } from '../api/invoiceApi';
import logger from 'redux-logger';
import { authMiddleware } from '../middleware/authMiddleware/authMiddleware';

const store = configureStore({
  reducer: {
    token: tokenReducer,
    [apiInvoices.reducerPath]: apiInvoices.reducer,
    // other reducers
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({})
      .concat(apiInvoices.middleware, authMiddleware, logger),
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

export default store

控制台输出(Token获取过晚)

Dispatching action: apiInvoices/config/middlewareRegistered authMiddleware.ts:15 [2024-11-14T08:06:58.937Z] Middleware: action is a function and started

authMiddleware.ts:15 [2024-11-14T08:06:58.937Z] middleware in action: apiInvoices/config/middlewareRegistered

authMiddleware.ts:25 Action in if: apiInvoices/config/middlewareRegistered

authMiddleware.ts:15 [2024-11-14T08:06:58.940Z] Token provider set

authMiddleware.ts:33 Token provider: e {_aadConfiguration: {…},
_oboConfiguration: {…}, _tokenAcquisitionEvent: e, onBeforeRedirectEvent: e, popupEvent: e, …}

authMiddleware.ts:19 Dispatching action: apiInvoices/executeQuery/pending

authMiddleware.ts:15 [2024-11-14T08:06:58.944Z] Middleware: action is a function and started

authMiddleware.ts:15 [2024-11-14T08:06:58.944Z] Middleware: action is a function and ended

authMiddleware.ts:42 action apiInvoices/executeQuery/pending @ 09:06:58.944

问题原因与解决方法

核心问题

  1. 你监听的apiInvoices/config/middlewareRegistered是RTK Query初始化动作,该动作执行完毕后RTK Query会立即发起请求,但你的中间件仅在初始化动作里处理Token,未拦截后续的请求动作。
  2. 混合使用await和.then()导致逻辑混乱,异步流程未正确阻塞请求动作的执行。

修正方案

1. 调整中间件拦截目标

改为监听RTK Query的请求发起动作,在请求前确保Token已就绪:

export const authMiddleware: Middleware =
  ({ dispatch, getState }) => next => async (action: PayloadAction) => {
    // 拦截RTK Query的请求动作
    if (action.type.startsWith('apiInvoices/executeQuery')) {
      const state = getState() as RootState;
      // 先从store取已有的Token(后续可添加过期判断)
      let token = state.token.getInvoiceByID;

      if (!token) {
        // 无有效Token则异步获取
        const tokenProvider = await getAadTokenProvider();
        if (tokenProvider) {
          token = await tokenProvider.getToken('6cbc9b1e-901d-4a99-a947-ae36ffe3ac38');
          // 将Token存入store
          dispatch(setToken({ endpoint: 'getInvoiceByID', token }));
        }
      }

      // Token存在才放行请求
      if (token) {
        return next(action);
      } else {
        console.error('获取认证Token失败');
        return;
      }
    }

    // 非目标动作直接放行
    return next(action);
  };

2. 调整中间件顺序

在store.ts中将authMiddleware放在apiInvoices.middleware之前,确保请求先经过Token处理:

middleware: (getDefaultMiddleware) =>
  getDefaultMiddleware({})
    .concat(authMiddleware, apiInvoices.middleware, logger),

3. 统一异步写法

避免await和.then()混用,全部使用await让逻辑更清晰易维护。


内容的提问来源于stack exchange,提问作者Jakub Husařík

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 06:21:04