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

如何在Redux asyncThunk中向客户端传递状态码?

解决Redux登录请求中获取服务器状态码的问题

问题根源

  • fetch API不会因4xx/5xx状态码自动抛出异常,仅网络错误才会触发reject
  • 服务器用res.sendStatus(401)返回的响应无响应体,执行result.json()会报错,导致createAsyncThunk进入rejected状态,但丢失了状态码信息
  • 当前Slice的rejected分支未保存错误信息,组件无法获取失败原因

解决方案

1. 修改后端返回格式,携带错误信息

将res.sendStatus(401)替换为带JSON响应体的形式,让前端能拿到明确的错误提示:

// server.js
app.post('/login', (req, res) => {
  const email = req.body.email;
  const plainTextPassword = req.body.password;
  User.find({ email: email }).limit(1).exec(function (err, existingUser) {
    if (existingUser.length === 0) {
      res.status(401).json({ message: "用户不存在", status: 401 });
    } else {
      bcrypt.compare(plainTextPassword, existingUser[0].password, function (err, response) {
        if (response === true) {
          req.session.user = existingUser[0]._id
          res.json({ session: req.session, status: 200 });
        } else {
          res.status(401).json({ message: "密码错误", status: 401 });
        }
      })
    }
  })
})

2. 改造createAsyncThunk,处理响应状态

在login异步action中先判断响应是否成功,若失败则主动抛出包含状态码和错误信息的异常,确保createAsyncThunk捕获到错误详情:

// userAuthSlice.js
export const login = createAsyncThunk(
    'userAuth/login',
    async (payload, thunkAPI) => {
        const { email, password } = payload
        const result = await fetch(
            loginPath, {
            mode: 'cors',
            credentials: 'include',
            method: 'post',
            body: JSON.stringify({ email, password }),
            headers: {
                'Content-Type': 'application/json'
            },
        })
        
        // 先检查响应状态
        if (!result.ok) {
            const errorData = await result.json().catch(() => ({ message: '请求失败' }));
            throw new Error(JSON.stringify({
                status: result.status,
                message: errorData.message
            }));
        }
        
        const response = await result.json()
        return response
    }
)

3. 更新Redux Slice,保存错误状态

在Slice的state中添加错误相关字段,并在fulfilled和rejected分支分别处理成功/失败状态:

// userAuthSlice.js
const userAuthSlice = createSlice({
    name: 'userAuth',
    initialState: {
        isLoading: false,
        isAuth: false,
        error: null,
        errorStatus: null
    },
    extraReducers: {
        [login.pending]: (state) => {
            state.isLoading = true
            state.error = null;
            state.errorStatus = null;
        },
        [login.fulfilled]: (state, action) => {
            state.isLoading = false
            state.isAuth = true
            state.error = null;
            state.errorStatus = null;
        },
        [login.rejected]: (state, action) => {
            state.isLoading = false
            state.isAuth = false;
            const errorInfo = JSON.parse(action.error.message);
            state.error = errorInfo.message;
            state.errorStatus = errorInfo.status;
        },
    }
})

export default userAuthSlice.reducer;

4. 在组件中获取错误信息并渲染

在loginModal中通过useSelector获取Redux状态,根据状态码渲染对应提示:

// loginmodal.js
import { useSelector, useDispatch } from 'react-redux';

const LoginModal = () => {
    const { error, errorStatus, isLoading } = useSelector(state => state.userAuth);
    const dispatch = useDispatch();
    // 假设email和password已通过useState定义
    
    const handleLogin = async (event) => {
        event.preventDefault();
        await dispatch(login({ email, password }));
    }
    
    return (
        <form onSubmit={handleLogin}>
            {/* 邮箱、密码输入框 */}
            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
            <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
            <button type="submit" disabled={isLoading}>登录</button>
            
            {isLoading && <div>登录中...</div>}
            {errorStatus === 401 && <div style={{color: 'red'}}>{error}</div>}
        </form>
    )
}

内容的提问来源于stack exchange,提问作者benwl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 22:27:29