登录失败时意外跳转到首页的问题排查求助(附相关代码)
登录失败时意外跳转到首页的问题排查求助(附相关代码)
各位好,我现在遇到一个很奇怪的问题,想请大家帮忙看看:
我在做一个Expo + Expo Router的项目,登录功能里,当用户输入错误的用户名/密码时,后端(NextJS)会返回401状态码和错误信息。按我的代码逻辑,这时候应该进入!res.success分支:打印调试日志、把错误信息存到state里显示出来,不会做任何跳转操作。
现在的问题是:调试日志确实打印了,错误提示也能短暂显示,但紧接着页面就会莫名其妙跳转到首页。我翻遍了整个代码库,都没找到任何主动跳转到首页的代码,完全搞不懂为什么会触发这个跳转...
相关代码片段
1. LoginForm.jsx 中的登录处理逻辑
const handleLogin = async () => { const fieldErrors = validate(); setErrors(fieldErrors); if (Object.keys(fieldErrors).length > 0) return; const res = await login(username, password); if (!res.success) { console.log("something is wrong") setErrors({ global: res.error }); } else { router.replace("/(drawer)/dashboard"); } }; return( // ... 其他表单元素 {errors.global && <Text style={styles.error}>{errors.global}</Text>} )
2. AuthContext 完整代码(认证上下文)
import { createContext, useState, useEffect, useContext, useRef } from "react"; import * as SecureStore from "expo-secure-store"; import { useRouter } from "expo-router"; import { AppState } from "react-native"; import { BASE_URL } from "../constants/config"; import { setAuthHandlers } from "../utils/axiosInstance"; export const AuthContext = createContext(null); export const AuthProvider = ({ children }) => { const [accessToken, setAccessToken] = useState(null); const [user, setUser] = useState(null); const [isLoading, setIsLoading] = useState(true); const isRefreshing = useRef(false); const router = useRouter(); // Store token securely const saveUser = async (user) => { setUser(user); await SecureStore.setItemAsync("user", JSON.stringify(user)); }; const saveToken = async (token) => { setAccessToken(token); await SecureStore.setItemAsync("accessToken", token); }; const removeToken = async () => { setAccessToken(null); await SecureStore.deleteItemAsync("accessToken"); }; const login = async (username, password) => { setIsLoading(true); try { const res = await fetch(`${BASE_URL}/en/login/mobile/api`, { method: "POST", headers: { "Content-Type": "application/json" }, credentials: "include", body: JSON.stringify({ username, password }), }); const data = await res.json(); if (res.ok) { await saveToken(data.accessToken); await saveUser(data.user); return { success: true }; } else { return { success: false, error: data.message || "Login failed" }; } } catch (err) { return { success: false, error: "Something went wrong. Please try again.", }; } finally { setIsLoading(false); } }; const refreshToken = async () => { if (isRefreshing.current) return false; isRefreshing.current = true; try { const res = await fetch(`${BASE_URL}/en/refresh/mobile/api`, { method: "POST", credentials: "include", }); const data = await res.json(); if (res.ok) { await saveToken(data.accessToken); return true; } return false; } catch { return false; } finally { isRefreshing.current = false; } }; const checkLoginStatus = async () => { setIsLoading(true); try { const token = await SecureStore.getItemAsync("accessToken"); const storedUser = await SecureStore.getItemAsync("user"); if (token) { setAccessToken(token); if (storedUser) { setUser(JSON.parse(storedUser)); } const refreshed = await refreshToken(); if (!refreshed) { await removeToken(); setUser(null); router.replace("/(auth)/login"); } } else { setUser(null); setAccessToken(null); } } catch (err) { console.error("Auth initialization error:", err); } finally { setIsLoading(false); } }; useEffect(() => { setAuthHandlers({ refreshToken, }); }, []); useEffect(() => { checkLoginStatus(); const interval = setInterval(() => { if (accessToken) refreshToken(); }, 10 * 60 * 1000); return () => clearInterval(interval); }, []); useEffect(() => { const sub = AppState.addEventListener("change", (state) => { if (state === "active" && accessToken) refreshToken(); }); return () => sub.remove(); }, []); return ( <AuthContext.Provider value={{ accessToken, user, isLoading, login, }} > {children} </AuthContext.Provider> ); }; export const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error("useAuth must be used within an AuthProvider"); } return context; };
我自己的排查思路(没找到原因)
- 确认了
handleLogin里的else分支只有在登录成功时才会跳转到仪表盘,失败分支确实没有跳转代码; - 检查了AuthContext里的所有路由操作,只有
checkLoginStatus里会跳转到登录页,没有跳首页的逻辑; - 怀疑过是不是Axios的拦截器?但我这里登录用的是原生fetch,Axios的拦截器是给其他请求用的,而且
setAuthHandlers里也没写跳转逻辑;
有没有大佬能帮我分析下,这个莫名的首页跳转可能是哪里触发的?
内容来源于stack exchange
相关产品推荐
相关产品推荐

