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

使用React+Redux+devise-JWT鉴权页面刷新自动登出、fetch报400错误怎么办

问题1:页面刷新后loggedIn变为false

原因

  1. Redux状态存储在运行内存中,页面刷新会自动重置为初始值,你仅将token存入localStorage,但未在应用初始化时读取localStorage内容恢复登录状态。
  2. 你的STORE_TOKEN reducer逻辑错误,直接返回仅包含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还未更新登录状态,甚至登录请求失败也会触发跳转。

修复方案

  1. 修改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 }))
    }
}
  1. 修改登录组件的提交逻辑,请求成功后再跳转:
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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 02:57:01