如何在Redux asyncThunk中向客户端传递状态码?
解决Redux登录请求中获取服务器状态码的问题
问题根源
fetchAPI不会因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
相关产品推荐
相关产品推荐

