React向Express发POST请求时出现Cannot read property of 'undefined'错误排查
我帮你梳理下问题所在,你的代码里有几处关键错误,导致不管密码对错都返回401,同时前端还弹出Cannot read property 'data' of undefined的类型错误。
一、后端代码的核心问题
1. matchPasswords 方法的错误实现
这是导致401的根本原因:你在matchPasswords里用了bcrypt.compare的回调版本,但在async函数里这种写法完全行不通——当你给bcrypt.compare传回调时,它不会返回Promise,所以await bcrypt.compare(...)其实是在等待一个undefined,最终matchPasswords总是返回undefined。这就导致foundUser && (await foundUser.matchPasswords(password))这个条件永远为false,不管密码是否正确,后端都会走到else分支返回401。
修复后的matchPasswords:
userSchema.methods.matchPasswords = async function (enteredPassword) { // 直接返回bcrypt.compare的Promise,async函数会自动处理resolve的布尔值 return bcrypt.compare(enteredPassword, this.password); };
2. Mongoose findOne 混合使用async/await和回调
你在async函数里给findOne传了回调,这会让await完全失效——Mongoose的findOne如果传回调,就不会返回Promise,你的await等于白写,代码逻辑会变得混乱,错误处理也容易出问题。
修复后的authUser控制器(纯async/await写法):
const authUser = asyncHandler(async (req, res, next) => { console.log('Hit'); const { email, password } = req.body; // 用await直接获取查询结果,抛弃回调写法 const foundUser = await User.findOne({ email }); if (!foundUser) { res.status(401); return next(new Error('Invalid credentials')); } // 调用修复后的matchPasswords,得到正确的布尔值 const isPasswordMatch = await foundUser.matchPasswords(password); if (isPasswordMatch) { res.json({ _id: foundUser._id, name: foundUser.name, email: foundUser.email, token: generateWebToken(foundUser._id), }); } else { res.status(401); next(new Error('Invalid credentials')); } });
二、前端Action Creator的笔误
你的loginUser错误处理部分有个明显的笔误:把error.response.data.message写成了error.response.message.data,这就导致当后端返回错误时,你试图读取error.response.message.data,但error.response.message根本不存在,所以会抛出Cannot read property 'data' of undefined的错误。
修复后的错误处理代码:
export const loginUser = ({ email, password }) => async (dispatch) => { try { dispatch({ type: USER_LOGIN_REQUEST }); const config = { headers: { 'Content-Type': 'application/json', }, }; const { data } = await axios.post( '/api/v1/users/login', { email, password }, config ); dispatch({ type: USER_LOGIN_SUCCESS, payload: data }); } catch (error) { dispatch({ type: USER_LOGIN_FAIL, payload: error.response && error.response.data.message ? error.response.data.message // 修正了属性读取顺序 : error.message, }); } };
最后验证
先修复后端的两个问题,再修正前端的笔误:
- 用正确凭证登录时,后端会返回200和用户数据,前端触发
USER_LOGIN_SUCCESS - 用错误凭证登录时,后端返回401,前端正确捕获错误信息触发
USER_LOGIN_FAIL
内容的提问来源于stack exchange,提问作者BlackMath

