Redux Toolkit Query中如何通过PUT请求实现Token刷新重认证
fetchBaseQuery 除了接收路径字符串作为参数,还支持接收请求配置对象,自定义请求方法、请求头、请求体等所有请求参数,完全可以满足PUT方法刷新Token的需求,不需要额外引入原生fetch实现。你之前遇到的页面刷新后场景失效问题,就是因为手写原生fetch没有复用fetchBaseQuery预置的baseUrl、请求头注入、凭证携带等全局配置,导致刷新请求参数不符合接口要求。
Token存储在localStorage中不影响方案实现,只要在fetchBaseQuery的prepareHeaders钩子中统一从localStorage读取Token注入请求头即可,重试原请求时会自动带上更新后的新Token。
实现代码
直接修改原重认证包装函数即可,参考实现如下:
import { fetchBaseQuery } from '@reduxjs/toolkit/query' import { loggedOut } from './authSlice' // 基础请求配置,统一处理Token注入 const baseQuery = fetchBaseQuery({ baseUrl: '/', // 统一从localStorage读取Token加请求头,不依赖Redux存储 prepareHeaders: (headers) => { const accessToken = localStorage.getItem('accessToken') if (accessToken) { headers.set('Authorization', `Bearer ${accessToken}`) } return headers }, // 如果接口需要携带Cookie,打开下面的配置 // credentials: 'include' }) const baseQueryWithReauth = async (args, api, extraOptions) => { let result = await baseQuery(args, api, extraOptions) // 命中401时尝试刷新Token if (result.error && result.error.status === 401) { // 传入对象配置发起PUT请求,和原生fetch配置规则一致 const refreshResult = await baseQuery( { url: '/refreshToken', method: 'PUT', // 如果接口要求Refresh Token放在请求体,在这里配置,按后端要求序列化即可 body: { refreshToken: localStorage.getItem('refreshToken') }, // 如果Refresh Token需要放在请求头,在这里补充headers配置 // headers: { // 'X-Refresh-Token': localStorage.getItem('refreshToken') // } }, api, extraOptions ) if (refreshResult.data) { // 更新localStorage中的Token const { accessToken, refreshToken: newRefreshToken } = refreshResult.data localStorage.setItem('accessToken', accessToken) if (newRefreshToken) { localStorage.setItem('refreshToken', newRefreshToken) } // 有Redux状态同步需求可以放开下面的代码 // api.dispatch(tokenReceived(refreshResult.data)) // 重试原始请求,此时prepareHeaders会自动读取新Token注入 result = await baseQuery(args, api, extraOptions) } else { // 刷新失败,清除本地凭证,执行登出逻辑 localStorage.removeItem('accessToken') localStorage.removeItem('refreshToken') api.dispatch(loggedOut()) } } return result }
补充说明
- 不要在重认证逻辑中混用原生
fetch:所有请求走封装好的baseQuery,才能统一复用全局配置,避免不同场景下请求参数不一致的问题,这也是你之前刷新页面场景功能异常的核心原因。 - 如果存在页面加载时并发多个接口同时返回401的场景,可以在逻辑外层加一个刷新Promise的缓存标记,避免重复发起多次Token刷新请求,属于可选优化项,不影响基础功能使用。
内容的提问来源于stack exchange,提问作者Arcadiusz
相关产品推荐
相关产品推荐

