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

自定义fetchBaseQuery实现错误处理:401错误时如何调度reducer?

RTK 自定义baseQuery处理401错误并调度reducer实现方案

核心实现逻辑

RTK Query的自定义baseQuery是对原生fetchBaseQuery的包装函数,函数入参的第二个参数api对象内置了store的dispatch方法,可直接调用调度你需要的reducer。

完整代码实现

import { fetchBaseQuery } from '@reduxjs/toolkit/query/react'
// 导入你自己业务中定义的slice action,比如用户登出、清空用户信息的action
import { logout, clearUserState } from './slices/userSlice'

// 初始化基础baseQuery,配置你的通用请求参数
const baseFetch = fetchBaseQuery({
  baseUrl: '/your-api-base-url', // 替换为你的后端接口统一前缀
  // 携带跨域凭证(如需传递cookie可开启)
  credentials: 'include',
  // 统一注入请求头,比如token
  prepareHeaders: (headers) => {
    const token = localStorage.getItem('access_token')
    if (token) {
      headers.set('Authorization', `Bearer ${token}`)
    }
    return headers
  }
})

// 自定义包装后的baseQuery
export const customBaseQuery = async (args, api, extraOptions) => {
  const response = await baseFetch(args, api, extraOptions)

  // 捕获401未授权错误
  if (response.error && response.error.status === 401) {
    // 直接使用api.dispatch调度你需要的reducer
    api.dispatch(clearUserState())
    api.dispatch(logout())
    // 可选:无权限时跳转到登录页,非组件环境直接修改location即可
    // window.location.replace('/login')
  }

  return response
}

接入使用

在你定义的api slice中,把createApi的baseQuery参数替换为上面写的customBaseQuery即可生效:

import { createApi } from '@reduxjs/toolkit/query/react'
import { customBaseQuery } from './customBaseQuery'

export const appApi = createApi({
  reducerPath: 'appApi',
  baseQuery: customBaseQuery, // 替换默认baseQuery
  endpoints: (builder) => ({
    // 你的业务接口定义
  })
})

注意事项

  • 自定义baseQuery入参的api对象除了dispatch,还提供getState方法,可直接获取store中的全局状态,不需要额外引入store实例,避免出现循环依赖问题
  • 如果需要实现401时自动刷新token并重试原请求,可在401判断分支中添加刷新token逻辑,刷新成功后重新调用baseFetch发起原请求再返回结果即可
  • 调度登出相关reducer后如果需要跳转路由,不需要依赖react-router的hooks,直接操作window.location即可实现全局跳转

内容的提问来源于stack exchange,提问作者murari_sabavath

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 03:36:04