应用登录功能实现遇运行时错误,求代码排查与修复
登录功能运行时错误排查与修复方案
问题背景
实现应用登录功能时出现运行时错误,相关前后端JavaScript代码如下,错误表现为触发运行时错误提示,但部分业务提示信息可正常显示。
相关代码
前端代码
const loginUser = async () => { // 字段校验 if (!login.username || !login.password) { setError('请填写所有字段'); return; } let response = await API.userLogin(login); if ( response.msg === '用户名不匹配' || response.msg === '密码不匹配' ) { setError('用户名或密码错误'); return; } if (response.isSuccess) { setError(''); sessionStorage.setItem( 'accessToken', `Bearer ${response.data.accessToken}` ); sessionStorage.setItem( 'refreshToken', `Bearer ${response.data.refreshToken}` ); setAccount({ username: response.data.username, name: response.data.name, }); isUserAuthenticated(true); navigate('/'); } else { setError('出现未知错误!'); } };
后端代码
export const loginUser = async (request, response) => { try { let user = await User.findOne({ username: request.body.username }); if (!user) { return response .status(401) .json({ msg: '用户名不匹配' }); } let match = await bcrypt.compare( request.body.password, user.password ); if (!match) return response .status(401) .json({ msg: '密码不匹配' }); if (match) { const accessToken = jwt.sign( user.toJSON(), process.env.ACCESS_SECRET_KEY, { expiresIn: '15m' } ); const refreshToken = jwt.sign(user.toJSON(), process.env.REFRESH_SECRET_KEY); const newToken = new Token({ token: refreshToken }); await newToken.save(); response.status(200).json({ accessToken: accessToken, refreshToken: refreshToken, name: user.name, username: user.username, }); } } catch (error) { console.log(error); response .status(500) .json({ msg: '用户登录时发生错误' }); } };
错误排查
- 前后端响应格式不匹配:
- 后端成功登录时未返回
isSuccess字段,也未将数据包裹在data对象中,但前端代码尝试判断response.isSuccess并访问response.data,导致response.isSuccess为undefined(进入else分支),且response.data为undefined,触发运行时错误。
- 后端成功登录时未返回
- 前端未捕获请求异常:
API.userLogin如果出现网络错误或非预期响应,await会抛出错误,但前端未用try/catch捕获,直接引发运行时错误。
- 错误响应判断逻辑脆弱:
- 前端直接访问
response.msg,若请求返回非JSON格式或网络失败,response不是预期对象,访问msg会报错。
- 前端直接访问
修复方案
后端代码修复:统一响应格式
给所有响应添加isSuccess字段明确标识请求状态,同时将成功数据包裹在data对象中,保持格式一致性:
export const loginUser = async (request, response) => { try { let user = await User.findOne({ username: request.body.username }); if (!user) { return response .status(401) .json({ isSuccess: false, msg: '用户名不匹配' }); } let match = await bcrypt.compare( request.body.password, user.password ); if (!match) return response .status(401) .json({ isSuccess: false, msg: '密码不匹配' }); const accessToken = jwt.sign( user.toJSON(), process.env.ACCESS_SECRET_KEY, { expiresIn: '15m' } ); const refreshToken = jwt.sign(user.toJSON(), process.env.REFRESH_SECRET_KEY); const newToken = new Token({ token: refreshToken }); await newToken.save(); response.status(200).json({ isSuccess: true, data: { accessToken: accessToken, refreshToken: refreshToken, name: user.name, username: user.username, } }); } catch (error) { console.log(error); response .status(500) .json({ isSuccess: false, msg: '用户登录时发生错误' }); } };
前端代码修复:异常捕获+匹配响应格式
添加try/catch捕获请求异常,根据后端统一的响应格式调整处理逻辑:
const loginUser = async () => { // 字段校验 if (!login.username || !login.password) { setError('请填写所有字段'); return; } try { const response = await API.userLogin(login); if (!response.isSuccess) { if (response.msg === '用户名不匹配' || response.msg === '密码不匹配') { setError('用户名或密码错误'); } else { setError(response.msg || '出现未知错误!'); } return; } setError(''); sessionStorage.setItem( 'accessToken', `Bearer ${response.data.accessToken}` ); sessionStorage.setItem( 'refreshToken', `Bearer ${response.data.refreshToken}` ); setAccount({ username: response.data.username, name: response.data.name, }); isUserAuthenticated(true); navigate('/'); } catch (error) { // 处理网络错误或请求异常 setError('网络错误,请稍后重试'); console.error('登录请求失败:', error); } };
额外说明
如果API.userLogin基于fetch实现,需确保它解析JSON并处理HTTP错误状态码,示例如下:
// 示例API.userLogin实现 const userLogin = async (loginData) => { const res = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(loginData) }); // 处理HTTP错误状态码 if (!res.ok) { const errorData = await res.json().catch(() => ({ msg: '请求失败' })); return { isSuccess: false, msg: errorData.msg }; } return res.json(); };
内容的提问来源于stack exchange,提问作者Piyush Keshri
相关产品推荐
相关产品推荐

