使用React+Redux+devise-JWT鉴权页面刷新自动登出、fetch报400错误怎么办
问题1:页面刷新后loggedIn变为false
原因
- Redux状态存储在运行内存中,页面刷新会自动重置为初始值,你仅将token存入
localStorage,但未在应用初始化时读取localStorage内容恢复登录状态。 - 你的
STORE_TOKENreducer逻辑错误,直接返回仅包含token的新对象,会覆盖原有state中loggedIn、currentUser等所有字段,触发该action后登录状态会直接失效。
修复方案(修改用户reducer)
import { SIGNUP_USER, LOGIN_USER, LOGOUT_USER, STORE_TOKEN } from '../actions/types' // 初始化时读取localStorage的token,初始化登录状态 const getInitialState = () => { const savedToken = localStorage.getItem('token') return { loggedIn: !!savedToken, currentUser: {}, token: savedToken || null } } const INITIAL_STATE = getInitialState() export default (state = INITIAL_STATE, action) => { switch(action.type){ case SIGNUP_USER: return { ...state, loggedIn: true, currentUser: action.payload.user, token: action.payload.token } case LOGIN_USER: return { ...state, loggedIn: true, currentUser: action.payload.user, token: action.payload.token } case LOGOUT_USER: localStorage.removeItem('token') return { ...state, currentUser: {}, loggedIn: false, token: null } case STORE_TOKEN: // 必须保留原有state字段,仅更新token return { ...state, token: action.payload.token, } default: return state } }
问题2:登录跳转逻辑异常
原因
loginUser是异步请求,你调用后立刻执行路由跳转,此时登录请求还未完成,redux还未更新登录状态,甚至登录请求失败也会触发跳转。
修复方案
- 修改loginUser action,返回Promise方便异步处理:
export function loginUser(data){ return (dispatch) => { return fetch("http://localhost:3000/login", { method: "post", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ user: { ...data } }) }) .then(resp => resp.json()) .then(json => { if (json.token) { localStorage.setItem('token', json.token) dispatch({ type: LOGIN_USER, payload: json }) return { success: true } } return { success: false, error: json.error } }) .catch(err => ({ success: false, error: err.message })) } }
- 修改登录组件的提交逻辑,请求成功后再跳转:
handleSubmit = async (e) =>{ e.preventDefault() const credentials = this.state const loginRes = await this.props.loginUser(credentials) if (loginRes.success) { this.props.history.push('/bookmarks') } else { // 可自行添加登录失败提示逻辑 console.error('登录失败:', loginRes.error) } }
问题3:fetch提交数据返回400 Bad Request
原因
devise-JWT要求所有需要鉴权的请求必须在请求头中携带JWT凭证,你提交数据的请求未携带对应凭证,后端无法识别用户身份就会返回400/401错误。
修复方案
所有需要鉴权的fetch请求都添加Authorization请求头,示例如下:
// 提交数据的请求通用格式 fetch("http://localhost:3000/你的接口地址", { method: "POST", headers: { "Content-Type": "application/json", // 从localStorage或redux中读取token添加到请求头 "Authorization": `Bearer ${localStorage.getItem('token')}` }, body: JSON.stringify(你要提交的参数) })
额外优化建议
可以在应用根组件componentDidMount生命周期中,携带本地存储的token请求后端/current_user接口,验证token有效性:如果token有效就更新redux中的currentUser信息,如果无效就清除本地token,重置登录状态跳转登录页,避免本地存储过期token仍显示已登录的问题。
内容的提问来源于stack exchange,提问作者Adri Dipietro
相关产品推荐
相关产品推荐

