NextAuth+AuthRoute环境下SWR请求先于Token设置致401问题排查
1. SWR请求发起时机早于Token设置
AuthRoute中通过useEffect设置Axios默认Token,但useEffect是组件渲染完成后才执行的。而子组件(QuoteList)中的SWR请求会在组件挂载时立刻触发,此时Axios的Authorization头还未被设置,导致首次请求无Token返回401。
2. Fetcher函数未返回Promise
useFetch.ts中的fetcher函数没有返回api.get()的Promise,导致SWR无法正确识别请求状态,会自动重试请求。此时Token已经通过useEffect设置完成,所以后续重试请求能成功,但首次请求必然401。
3. 潜在的Session字段拼写错误
QuoteList中写了session?.data?.access_token,但NextAuth配置中session的Token字段是accessToken(驼峰),虽然useFetch中用了正确的session.data.accessToken,但这个拼写错误可能导致其他逻辑异常。
1. 修正Fetcher函数,确保返回Promise
修改useFetch.ts中的fetcher,返回完整的Promise链:
const fetcher = (url) => { return api .get(url, { withCredentials: true, }) .then((res) => { console.log(res.data); return res.data; }); };
2. 提前Token设置时机,避免依赖useEffect
在AuthRoute中,确认Session存在后立刻设置Token,而不是等到useEffect执行。因为AuthRoute已经通过status !== 'loading' && userExists判断后才渲染子组件,此时可以直接同步设置Token:
const AuthRoute = ({ children }) => { const { data: session, status } = useSession({ required: true }); const userExists = !!session?.user; const router = useRouter(); useEffect(() => { if (status !== 'loading' && !userExists) { router.push('/auth/login'); } }, [status, userExists, router]); // 同步设置Token,无需等待useEffect if (status === 'loading' || !userExists) { return <div>Waiting</div>; } setToken(session.accessToken); return children; };
这样子组件渲染时,Axios的默认头已经设置完成,SWR首次请求就能携带Token。
3. 优化SWR请求触发条件(可选)
在useFetch中,确保只有当Session和Token都明确存在时才生成SWR的key,避免无效请求:
export function useFetchQuotes( session, filters, paginationModel = { page: 0, pageSize: 10 }, ) { console.log('useFetchQuotes', session); // 确保session.data和accessToken都存在才发起请求 const swrKey = session?.data?.accessToken ? `url goes here` // 替换为实际请求URL : null; const { data, error, isLoading } = useSWR(swrKey, fetcher); let count = 5; return { data, error, isLoading, count }; }
4. 修正Session字段拼写错误
将QuoteList中的session?.data?.access_token改为session?.data?.accessToken,保持和NextAuth配置一致:
const headers = { Authorization: `Bearer ${session?.data?.accessToken}` };
内容的提问来源于stack exchange,提问作者nessj1994

