Axios登录请求异常:成功时仍触发catch块求助
问题排查与解决方案
嘿,咱们来拆解下你遇到的这个“then和catch同时执行”的问题——核心原因其实有两个,咱们一步步理清楚:
问题根源
async/await 与 .then/.catch 混合使用导致错误处理混乱
你在handleLogin这个async函数里同时混用了await和.then/.catch链式调用。async函数本身会返回一个Promise,一旦.then回调内部抛出未捕获的错误,这个错误会直接冒泡到外层的.catch块,就会出现你看到的“两边逻辑都执行”的诡异情况。.then回调里存在未捕获的运行时错误
重点看你.then里的this.InEmail.focus()——这里的this指向大概率出问题了!因为你用的是箭头函数作为.then的回调,箭头函数的this继承自定义它时的外层上下文,而不是组件实例。当你调用this.InEmail时,大概率拿到的是undefined,再调用focus()就会抛出错误,这个错误没被处理,直接触发了外层的.catch块。
修复方案:统一用 async/await + try/catch(推荐)
把混合写法改成纯async/await风格,错误处理更清晰,同时修正this指向的问题(如果是React Native项目,建议用useRef获取输入框引用)。
修改后的代码示例:
// 先在组件里定义输入框的ref(假设是函数组件) const emailRef = useRef(null); async function handleLogin() { try { // 清除旧的登录存储 await AsyncStorage.removeItem('Authorization'); await AsyncStorage.removeItem('ImAuthenticated'); // 发起登录请求 const response = await api.post('/login', { email, password }, { headers: { 'device': 'mobile' } }); const { hash } = response.data; // 存储登录状态(注意:AsyncStorage只能存字符串) await AsyncStorage.setItem("Authorization", hash); await AsyncStorage.setItem("ImAuthenticated", "true"); // 跳转到菜单页 navigation.navigate('Menu'); console.log('oi'); } catch (error) { // 统一处理所有错误:包括请求失败、代码运行时错误 if (error.response?.data?.showIn === "text") { setShowInfo(true); setEmail(''); setPass(''); emailRef.current?.focus(); // 用ref安全获取输入框并聚焦 setColorInfo(error.response.data.level !== 3); setInfoText(error.response.data.error); } else { setshowBox(true); setEmail(''); setPass(''); emailRef.current?.focus(); setcolorBox(error.response.data.level !== 3); setboxText(error.response.data.error); } } }
关键修复点
- 移除混合写法:用
try/catch统一处理所有错误,包括请求失败和代码运行时错误,避免错误冒泡混乱。 - 修正AsyncStorage存储类型:AsyncStorage只能存储字符串,你之前存布尔值
true会被自动转成字符串,但显式写"true"更稳妥。 - 修复输入框聚焦的this问题:用
useRef获取输入框实例,替代this.InEmail,彻底解决this指向错误。 - 添加可选链操作符:
error.response?.data避免了当error没有response属性时抛出新的错误,让错误处理更健壮。
如果你坚持要用.then/.catch写法
那需要在.then的回调内部也加一个try/catch,捕获回调里的运行时错误:
// 同样先定义ref const emailRef = useRef(null); async function handleLogin(){ await AsyncStorage.removeItem('Authorization'); await AsyncStorage.removeItem('ImAuthenticated'); await api.post('/login', { email, password }, { headers: { 'device': 'mobile' } }) .then(async(response)=>{ try { const { hash } = response.data; await AsyncStorage.setItem("Authorization", hash); await AsyncStorage.setItem("ImAuthenticated", "true"); navigation.navigate('Menu'); console.log('oi'); } catch (innerError) { // 处理.then回调内部的错误,比如AsyncStorage或navigation的错误 console.error('Then回调内部错误:', innerError); } }).catch(function (error){ // 原来的错误处理逻辑 if(error.response.data.showIn == "text"){ setShowInfo(true); setEmail(''); setPass(''); emailRef.current?.focus(); setColorInfo(error.response.data.level !== 3); setInfoText(error.response.data.error); }else{ setshowBox(true); setEmail(''); setPass(''); emailRef.current?.focus(); setcolorBox(error.response.data.level !== 3); setboxText(error.response.data.error); } }); }
不过还是更推荐第一种纯async/await + try/catch的写法,代码可读性和维护性更强,错误处理逻辑也更直观。
内容的提问来源于stack exchange,提问作者tomas
相关产品推荐
相关产品推荐

