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

React-Redux电商应用:仅登录时加载用户与Stripe密钥方案

问题描述

这是一个电商Web应用,支持用户添加商品至购物车,注册/登录后可进行支付。当前问题:首页加载时,若用户未登录,开发者工具会出现以下401未授权错误:

GET http://.../profile 401 (Unauthorized)
GET http://.../stripeapikey 401 (Unauthorized)

解决方案

核心思路是仅在用户已登录(持有有效认证凭证)时,才发起需要授权的接口请求,具体修改如下:

1. 控制App初始化时的请求触发逻辑

修改App.js,在发起loadUser和获取Stripe密钥前,先检查本地是否存储了用户认证token(通常登录成功后会将token存在localStorage或sessionStorage),只有存在token时才执行这些操作:

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { useEffect, useState } from 'react'
import { Elements } from '@stripe/react-stripe-js'
import { loadStripe } from '@stripe/stripe-js'
import axios from 'axios'

import Header from './components/Header'
import Home from './components/Home'
import Payment from './components/Payment'
import Profile from './components/Profile'

import { loadUser } from './actions/user'
import store from './store'

export default function App() {

  const [stripeApiKey, setStripeApiKey] = useState('')

  useEffect(() => {
    // 先检查本地是否有认证token
    const authToken = localStorage.getItem('token') // 假设token存在localStorage的'token'键中
    if (authToken) {
      store.dispatch(loadUser());
      
      (async () => {
        try {
          const { data } = await axios.get('/api/stripeapikey')
          setStripeApiKey(data.stripeApiKey)
        } catch (err) {
          console.error('获取Stripe密钥失败:', err)
        }
      })()
    }
  }, [])

  return (
    <Router>
      <div className="App">
        <Header />
        <Routes>
          <Route path="/" element={<Home />} />
          {/* These 2 routes are protected */}
          <Route path="profile" element={<Profile />} />
          {stripeApiKey &&
            <Route path="payment"
              element={<Elements stripe={loadStripe(stripeApiKey)}><Payment /></Elements>}
            />
          }
        </Routes>
      </div>
    </Router>
  )
}

2. 优化loadUser Action,提前拦截无授权请求

修改actions/user.js,在发起请求前先检查是否存在认证token,避免无意义的接口调用:

import axios from 'axios'

export const loadUser = () => async dispatch => {
    // 先检查本地token
    const authToken = localStorage.getItem('token')
    if (!authToken) {
        dispatch({
            type: 'LOAD_USER_FAIL',
            payload: '未登录,请先登录'
        })
        return
    }

    try {
        dispatch({ type: 'LOAD_USER_REQ' })
        // 确保axios携带token(如果后端需要在请求头传递)
        const config = {
            headers: {
                'Authorization': `Bearer ${authToken}`
            }
        }
        const { data } = await axios.get('/api/profile', config)

        dispatch({
            type: 'LOAD_USER_SUCCESS',
            payload: data.user
        })

    } catch (error) {
        dispatch({
            type: 'LOAD_USER_FAIL',
            payload: error.response?.data?.message || '加载用户信息失败'
        })
    }
}

export const clearErrors = () => async dispatch => {
    dispatch({ type: 'CLEAR_ERRORS' })
}

3. 调整Redux初始状态(可选优化)

修改reducers/user.js,初始状态根据本地token判断认证状态,让UI渲染更准确:

// 从localStorage获取token,初始化认证状态
const initialState = {
    loading: false,
    isAuthenticated: !!localStorage.getItem('token'),
    user: localStorage.getItem('token') ? {} : null,
    error: null
}

export const authReducer = (state = initialState, action) => {
    switch (action.type) {

        case 'LOAD_USER_REQ':
            return {
                ...state,
                loading: true,
                isAuthenticated: false
            }

        case 'LOAD_USER_SUCCESS':
            return {
                ...state,
                loading: false,
                isAuthenticated: true,
                user: action.payload,
                error: null
            }

        case 'LOAD_USER_FAIL':
            return {
                ...state,
                loading: false,
                isAuthenticated: false,
                user: null,
                error: action.payload
            }

        case 'CLEAR_ERRORS':
            return {
                ...state,
                error: null
            }

        default:
            return state
    }
}

补充说明

  • 确保后端接口/api/profile和/api/stripeapikey确实需要用户登录才能访问,若后端有对应的权限校验逻辑,前端的上述修改就能完全避免未登录时的401错误。
  • 登录成功后,记得将后端返回的token存入localStorage或sessionStorage,同时dispatchLOAD_USER_SUCCESS更新Redux状态;登出时删除token并dispatchLOAD_USER_FAIL或对应的登出action。

内容的提问来源于stack exchange,提问作者5fingered sloth

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 16:22:04