NextJS客户端请求自动添加Access Token失效及Token刷新问题排查
问题排查与解决方案
一、客户端请求无法自动附加Token的问题
1. 检查Cookie的HttpOnly属性
登录时用nookies.set存储Token时,如果设置了HttpOnly: true,客户端JS无法读取该Cookie,拦截器自然取不到Token。服务端能正常获取是因为服务端不受HttpOnly限制。
- 错误示例(客户端无法读取):
nookies.set(ctx, 'accessToken', token, { httpOnly: true, path: '/', maxAge: 3600 }) - 修正方案(移除
HttpOnly,配合安全属性降低风险):nookies.set(ctx, 'accessToken', token, { httpOnly: false, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', path: '/', maxAge: 3600 })
2. 客户端正确读取Cookie的写法
nookies在客户端和服务端的API有差异,客户端读取Cookie需传入null作为第一个参数:
import nookies from 'nookies' import axios from 'axios' const axiosInstance = axios.create({ baseURL: process.env.NEXT_PUBLIC_API_URL }) // 客户端请求拦截器 axiosInstance.interceptors.request.use(config => { const cookies = nookies.get(null) const accessToken = cookies.accessToken if (accessToken) { config.headers.Authorization = `Bearer ${accessToken}` } return config })
3. 确保拦截器全局生效
要保证Axios实例全局复用,且拦截器在客户端环境初始化(比如在_app.tsx中完成初始化,避免仅在服务端代码中配置):
// pages/_app.tsx import axiosInstance from '../utils/axios' function MyApp({ Component, pageProps }) { // 确保拦截器在客户端初始化 useEffect(() => { // 若拦截器已在axios实例文件中初始化,此步可省略 }, []) return <Component {...pageProps} /> }
二、Token刷新逻辑异常的问题
1. 避免刷新请求进入循环
刷新Token的请求本身不需要携带旧Access Token,否则会触发拦截器重复刷新,导致循环:
axiosInstance.interceptors.response.use( response => response, async error => { const originalRequest = error.config // 仅处理403且未尝试过刷新的请求 if (error.response.status === 403 && !originalRequest._retry) { originalRequest._retry = true try { // 刷新请求不携带Authorization头,开启withCredentials传递Refresh Token的Cookie const refreshRes = await axios.post(`${process.env.NEXT_PUBLIC_API_URL}/token/refresh`, {}, { withCredentials: true }) const newToken = refreshRes.data.accessToken // 更新Cookie中的Token nookies.set(null, 'accessToken', newToken, { httpOnly: false, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', path: '/', maxAge: 3600 }) // 更新原请求头并重发 originalRequest.headers.Authorization = `Bearer ${newToken}` return axiosInstance(originalRequest) } catch (refreshErr) { // 刷新失败跳转登录页 window.location.href = '/login' return Promise.reject(refreshErr) } } return Promise.reject(error) } )
2. 确认Refresh Token的传递逻辑
如果Refresh Token存在Cookie中,必须开启withCredentials: true让浏览器自动携带;如果存在localStorage或其他存储,需手动将其加入请求头或请求体。
3. 检查后端刷新接口逻辑
确认后端/token/refresh接口能正确识别Refresh Token(从Cookie或请求参数中获取),返回有效的新Access Token,同时处理Refresh Token过期的场景。
内容的提问来源于stack exchange,提问作者kd12345
相关产品推荐
相关产品推荐

