RTK Query无法携带授权Token获取用户配置文件问题求助
RTK Query无法在请求头中携带Token获取用户配置文件
问题描述
在React + Redux Toolkit(RTK)课程项目中,已通过RTK Query的POST请求完成登录并成功获取Token,但调用获取用户配置文件的POST接口(/user/profile)时,无法将Token放入请求头。核心问题是getState().auth.data.body.token无法正确获取Token,不清楚状态的正确路径。
API信息
- POST
/user/login:请求正常,返回包含Token的响应 - POST
/user/profile:需在请求头携带Token才能获取响应,目前无法成功请求
相关代码
store.js
import { configureStore } from '@reduxjs/toolkit' import { bankApi } from './ApiSlice.js' export const store = configureStore({ reducer: { [bankApi.reducerPath]: bankApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(bankApi.middleware), })
ApiSlice.js
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' const apiBaseUrl = 'http://localhost:3001/api/v1'; export const bankApi = createApi({ reducerPath: 'bankApi', baseQuery: fetchBaseQuery({ baseUrl: apiBaseUrl, prepareHeaders: (headers, { getState }) => { console.log('prepareHeaders is called'); const token = getState().auth.data.body.token; if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; }, }), endpoints: (builder) => ({ auth: builder.mutation({ query: (credentials) => ({ url: '/user/login', method: 'POST', body: credentials, }), }), getProfile: builder.mutation({ query: () => ({ url: '/user/profile', method: 'POST', }), }), updateProfile: builder.query({ query: () => ({ url: '/user/profile', method: 'PUT', }), }), }), }) export const { useAuthMutation, useGetProfileMutation, useUpdateProfileQuery } = bankApi
Loginpage.jsx
import { useState } from 'react'; import { useAuthMutation, useGetProfileMutation } from '../rtk/ApiSlice' export default function LoginPage(){ const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [ login, { isLoading: loginIsLoading, isError: loginIsError, isSuccess: loginIsSuccess, data: loginData, error: loginError } ] = useAuthMutation(); const [ profile, { isError: profileIsError, error: profileError, data: profileData } ] = useGetProfileMutation(); const handleLogin = (e) => { e.preventDefault(); login({ email, password }); }; const handleProfile = () => { profile(); }; return ( <div className="main bg-dark"> <section className="sign-in-content"> <i className="fa fa-user-circle sign-in-icon"></i> <h1>Sign In</h1> <form onSubmit={(e) => { e.preventDefault(); handleLogin(); }} > <div className="input-wrapper"> <label>Username</label> <input type="text" id="email" placeholder="" value={email} onChange={(e) => setEmail(e.target.value)} /> </div> <div className="input-wrapper"> <label>Password</label> <input type="password" id="password" placeholder="" value={password} onChange={(e) => setPassword(e.target.value)} /> </div> <div className="input-remember"> <input type="checkbox" id="remember-me" /> <label>Remember me</label> </div> <button className="sign-in-button" type="submit" disabled={loginIsLoading} > {loginIsLoading ? 'Signing in...' : 'Sign in'} </button> </form> {loginIsError && <p className='perror'> {loginError.data.status} {loginError.data.message} </p>} {loginIsSuccess && <> <p className='psuccess'> {loginData.message} Token: {loginData.body.token} </p> <button onClick={handleProfile}> Get Profile </button> </>} {profileIsError && <p className='perror'> {profileError.data.status} {profileError.data.message} </p>} {profileData && <p className='psuccess'> {profileData.message} First Name: {profileData.body.firstName} Last Name: {profileData.body.lastName} Surname: {profileData.body.userName} </p>} </section> </div> ); }
已尝试的解决方法
- 查阅RTK Query官方文档
- 观看RTK Query相关教程
- 通过
prepareHeaders尝试获取并设置Token - 在
getProfile接口中单独配置prepareHeaders - 在Loginpage.jsx中直接传递Token给
useGetProfileMutation - 将Token存入
localStorage后取出使用 - 等待登录成功后再调用获取配置文件接口
解决方案
问题根源
你的Redux Store中仅注册了RTK Query的bankApi reducer,不存在名为auth的切片,因此getState().auth路径无效。RTK Query的mutation响应数据默认存储在bankApi的缓存中,但该缓存路径不稳定,不建议直接读取。
方法一:创建独立Auth切片存储Token
1. 新建authSlice.js
import { createSlice } from '@reduxjs/toolkit'; const initialState = { token: null, }; const authSlice = createSlice({ name: 'auth', initialState, reducers: { setToken: (state, action) => { state.token = action.payload; }, clearToken: (state) => { state.token = null; }, }, }); export const { setToken, clearToken } = authSlice.actions; export default authSlice.reducer;
2. 更新store.js,添加Auth reducer
import { configureStore } from '@reduxjs/toolkit' import { bankApi } from './ApiSlice.js' import authReducer from './authSlice.js' export const store = configureStore({ reducer: { auth: authReducer, [bankApi.reducerPath]: bankApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(bankApi.middleware), })
3. 修改Loginpage.jsx,登录成功后保存Token
import { useState } from 'react'; import { useDispatch } from 'react-redux'; import { useAuthMutation, useGetProfileMutation } from '../rtk/ApiSlice'; import { setToken } from '../rtk/authSlice'; export default function LoginPage(){ const dispatch = useDispatch(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [ login, { isLoading: loginIsLoading, isError: loginIsError, isSuccess: loginIsSuccess, data: loginData, error: loginError } ] = useAuthMutation(); const [ profile, { isError: profileIsError, error: profileError, data: profileData } ] = useGetProfileMutation(); const handleLogin = (e) => { e.preventDefault(); login({ email, password }).unwrap() .then((data) => { dispatch(setToken(data.body.token)); }) .catch((err) => { // 处理登录错误 }); }; // 其余代码保持不变 }
4. 更新ApiSlice.js的prepareHeaders路径
prepareHeaders: (headers, { getState }) => { console.log('prepareHeaders is called'); const token = getState().auth.token; if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; },
方法二:使用localStorage存储Token(更简单)
1. 修改Loginpage.jsx的登录逻辑
const handleLogin = (e) => { e.preventDefault(); login({ email, password }).unwrap() .then((data) => { localStorage.setItem('authToken', data.body.token); }) .catch((err) => { // 处理登录错误 }); };
2. 更新ApiSlice.js的prepareHeaders
prepareHeaders: (headers) => { const token = localStorage.getItem('authToken'); if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; },
补充说明
- 方法一使用Redux状态管理Token,适合需要全局共享登录状态的场景;方法二使用localStorage,实现更简单,且页面刷新后Token不会丢失。
- 注意:使用localStorage存储Token时,需考虑XSS攻击风险,可结合其他安全措施(如HttpOnly Cookie),但课程项目中可暂时使用该方案。
内容的提问来源于stack exchange,提问作者Bidou
相关产品推荐
相关产品推荐

