Next.js无需useEffect,Token过期时递归调用API的实现问题
解决Next.js中提交表单时token过期的重试问题
核心问题拆解
你当前面临两个关键问题:递归调用时的TypeScript类型不匹配,以及无限制重试导致无限循环的风险。根源在于直接复用FormEvent参数,且未对重试次数做限制。
解决方案步骤
1. 抽离核心提交逻辑,摆脱事件依赖
把API提交的核心逻辑从handleSubmit中拆分出来,写成独立函数,彻底避免对FormEvent的依赖,从根源解决类型问题:
// 抽离独立的提交函数,仅依赖token和产品数据 const submitProduct = async (currentAccessToken: string) => { const productData = { productName, brand, productDescription, stockQuantity, retailPrice, COGS, variants, warehouse_enter_date, exp_date, imageURL, }; const response = await fetch("http://localhost:4000/dashboard/product/new", { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${currentAccessToken}`, }, body: JSON.stringify(productData), }); if (!response.ok) { if (response.status === 403) { // 返回标记表示需要刷新token return { needsRefresh: true }; } throw new Error("Failed to create product"); } const responseData = await response.json(); if (!responseData?.product?._id) { throw new Error("Invalid response data from server"); } return { success: true, data: responseData }; };
2. 修改handleSubmit,加入重试控制和token刷新逻辑
在事件处理函数中限制重试次数(最多1次),避免refresh token失效时陷入无限循环,同时处理token刷新后的重新提交:
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); let retryCount = 0; const maxRetries = 1; // 限制最多重试1次,防止无限循环 while (retryCount <= maxRetries) { try { const result = await submitProduct(accessToken); if (result.needsRefresh) { // 等待token刷新完成,必须加await await updateTokens(refreshToken); // 从localStorage读取新token(若用状态管理可直接取状态) const newAccessToken = localStorage.getItem("accessToken"); if (!newAccessToken) throw new Error("Failed to get new access token"); retryCount++; // 用新token重新提交 const retryResult = await submitProduct(newAccessToken); if (retryResult.success) { router.push(`/dashboard/product/${retryResult.data.product._id}`); return; } } else if (result.success) { router.push(`/dashboard/product/${result.data.product._id}`); return; } } catch (error) { if (error instanceof Error) { console.error("Error creating product:", error.message); } else { console.error("Unknown error:", error); } break; // 出错直接终止,不再重试 } } };
3. 关键细节说明
- 异步等待token刷新:必须给
updateTokens加await,否则token还未更新完成就重新提交,会继续使用旧token导致403。 - 重试次数限制:设置
maxRetries为1,因为如果refresh token也失效,再重试毫无意义,直接终止避免无限循环。 - 新token的获取:假设
updateTokens会将新token存入localStorage,刷新后需重新读取;若使用状态管理(如useState、Redux),可直接同步读取状态,更高效。
额外优化建议
- 将token存在React状态中,而非每次从localStorage读取,更新后状态自动同步,减少手动操作。
- 封装全局请求拦截器(如用Axios),让所有API请求自动处理403刷新逻辑,不用每个提交函数重复编写。
内容的提问来源于stack exchange,提问作者Linh Tran
相关产品推荐
相关产品推荐

