使用Ky发起请求遇403重试时,Access Token无法更新如何解决?
解决Ky请求403重试时Token未更新的问题
问题核心:使用Ky发起请求时,遇到403错误刷新Token后,重试请求仍携带旧Token。
问题根源
beforeRequest钩子初始化时通过闭包捕获了旧的auth值,React状态更新后闭包内的auth不会同步变更;- 重试触发时
beforeRequest会再次执行,用旧Token覆盖你在beforeRetry中设置的新Token。
解决方案
1. 用Ref保存最新Token
通过useRef规避闭包陷阱,确保beforeRequest能获取到实时的Token值:
export const useKy = () => { const { auth, setAuth, refreshToken } = useAuth(); // 用ref保存最新token,不受闭包限制 const authRef = useRef(auth); // 同步状态更新到ref useEffect(() => { authRef.current = auth; }, [auth]); const customKy = ky.extend({ prefixUrl: 'api/v1', hooks: { beforeRequest: [ async (request) => { // 使用ref中的最新token设置请求头 if (authRef.current) { request.headers.set('Authorization', `Bearer ${authRef.current}`); } request.headers.set('Content-Type', 'application/json'); }, ], beforeRetry: [ async ({ request, error, retryCount }) => { if (error instanceof HTTPError && error.response.status === 403 && retryCount === 1) { try { const newAccessToken = await refreshToken(); // 更新全局auth状态 setAuth(newAccessToken.access_token); // 直接修改当前请求头,确保重试用新token request.headers.set('Authorization', `Bearer ${newAccessToken.access_token}`); } catch (err) { throw new Error('Failed to refresh token'); } } }, ], }, retry: { methods: ['get', 'post'], limit: 3, statusCodes: [403], }, }); return { customKy }; };
2. 可选:避免请求头重复覆盖
如果担心beforeRequest和beforeRetry的执行顺序导致冲突,可以在beforeRequest中判断请求头是否已存在Authorization,仅在未设置时赋值:
beforeRequest: [ async (request) => { // 仅当请求头无Authorization时才设置 if (!request.headers.has('Authorization') && authRef.current) { request.headers.set('Authorization', `Bearer ${authRef.current}`); } request.headers.set('Content-Type', 'application/json'); }, ],
效果说明
authRef会实时同步最新的Token值,彻底解决闭包导致的旧值问题;beforeRetry中直接修改请求头,确保重试请求立刻携带新Token;- 即使
beforeRequest在重试时再次执行,也会使用最新Token或跳过重复设置。
内容的提问来源于stack exchange,提问作者magrega
相关产品推荐
相关产品推荐

