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

如何用Redux Toolkit的createMiddlewareListener实现页面登录前置校验?

用Redux Toolkit的Listener Middleware实现页面登录校验

首先纠正一点:Redux Toolkit里并没有createMiddlewareListener这个API,你需要用的是**createListenerMiddleware**(属于@reduxjs/toolkit的listener middleware功能),用来监听特定动作(比如路由跳转)并执行登录校验逻辑。以下是具体实现步骤:

步骤1:创建Listener Middleware并定义校验逻辑

新建一个文件(比如authListener.js),创建listener实例并监听路由跳转动作,触发登录状态校验:

import { createListenerMiddleware } from '@reduxjs/toolkit';
import { loginApi } from './你的loginApi路径';
import TokenUtil from './你的TokenUtil路径';
// 如果你用react-router,导入路由变化的action(需配合react-router-redux或自定义导航action)
import { LOCATION_CHANGE } from 'react-router-redux';

// 创建listener middleware实例
export const authListenerMiddleware = createListenerMiddleware();

// 添加登录校验监听器
authListenerMiddleware.startListening({
  // 监听路由跳转动作
  actionCreator: LOCATION_CHANGE,
  // 过滤需要校验的页面:排除登录页,其他页面都触发校验
  predicate: (action) => {
    const { pathname } = action.payload.location;
    return pathname !== '/login';
  },
  async effect(action, listenerApi) {
    // 先检查本地是否存在token
    const token = TokenUtil.getToken();
    if (!token) {
      window.location.href = '/login';
      return;
    }

    try {
      // 调用getMe接口校验token有效性
      const result = await listenerApi.dispatch(loginApi.endpoints.getMe.initiate());
      
      if (result.isError) {
        // token无效则清除并跳转登录页
        TokenUtil.clearToken();
        window.location.href = '/login';
      }
      // 校验通过则正常访问页面
    } catch (error) {
      console.error('登录校验失败:', error);
      TokenUtil.clearToken();
      window.location.href = '/login';
    }
  },
});

步骤2:优化API的Token获取方式

你当前的getMe接口直接硬编码token获取逻辑,建议改用fetchBaseQuery的prepareHeaders动态设置,确保token更新时能自动同步:

export const loginApi = createApi({
  reducerPath: "loginApi",
  tagTypes: ["Login"],
  baseQuery: fetchBaseQuery({ 
    baseUrl: appConfig.apiUrl, 
    jsonContentType: "application/json",
    // 动态设置请求头
    prepareHeaders: (headers) => {
      const token = TokenUtil.getToken();
      if (token) {
        headers.set('Authorization', `Bearer ${token}`);
      }
      return headers;
    }
  }),
  endpoints: (build) => ({
    login: build.mutation({
      query: ({ username, password }) => ({
        url: "/auth/login",
        method: "POST",
        body: { username, password },
      }),
      // 登录成功后自动保存token到本地
      async onQueryStarted(args, { queryFulfilled }) {
        try {
          const { data } = await queryFulfilled;
          TokenUtil.setToken(data.token); // 假设接口返回token字段
        } catch (error) {
          console.error('登录失败:', error);
        }
      }
    }),
    getMe: build.query({
      query: () => "/auth/me", // 无需手动设置headers,prepareHeaders会自动处理
    }),
  }),
});

export const { useLoginMutation, useGetMeQuery } = loginApi;

步骤3:将Listener Middleware加入Store配置

修改你的configureStore代码,把authListenerMiddleware加入到中间件数组中:

import { configureStore } from '@reduxjs/toolkit';
import { loginApi } from './你的loginApi路径';
import { authListenerMiddleware } from './你的authListener路径';

export const store = configureStore({
  reducer: {
    [loginApi.reducerPath]: loginApi.reducer,
    //...其他reducers
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      .concat(loginApi.middleware)
      .prepend(authListenerMiddleware.middleware), // prepend确保校验逻辑优先执行
});

补充说明

  • 如果你没有使用react-router-redux,可以在页面组件的useEffect中触发自定义action(比如dispatch({ type: 'page/load', payload: { pathname } })),然后在listener中监听该action。
  • 可根据业务需求调整predicate逻辑,过滤不需要校验的公开页面。

内容的提问来源于stack exchange,提问作者Dharma Fattahul Winzi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 08:56:11