Next.js中cookies-next与Axios拦截器集成问题排查
问题根源
cookies-next库在服务端和客户端的Cookie处理逻辑存在差异:
- 服务端环境下,
setCookie依赖req和res对象通过HTTP响应头写入Cookie,若不传这两个参数,服务端无法完成Cookie设置 - 客户端环境下,若未指定
path、maxAge等关键配置,可能导致Cookie仅在局部路径生效或立即过期,表现为设置无效
解决方案
1. 适配服务端场景:传入req/res参数
当Axios拦截器在服务端执行(如API路由、服务端组件中调用),必须将req和res传递给setCookie。以下是修改后的完整代码:
import axios from "axios"; import { getCookie, setCookie } from "cookies-next"; const axiosUser = axios.create({ baseURL: process.env.NEXT_PUBLIC_BASE_URL_USER, headers: { "Content-Type": "application/json" }, withCredentials: true, }); const axiosLogin = axios.create({ baseURL: process.env.NEXT_PUBLIC_BASE_URL_USER, headers: { "Content-Type": "application/json" }, withCredentials: true, }); axiosUser.interceptors.request.use( async (config) => { // 服务端读取Cookie需传入req const token = getCookie("TOKEN", { req: config.req }); console.log("««««« token »»»»»", token); // 若需在请求头携带Token,添加以下代码 // if (token) config.headers.Authorization = `Bearer ${token}`; return config; }, (error) => Promise.reject(error), ); axiosLogin.interceptors.response.use( async (response) => { const { token, refreshToken } = response.data; // 从请求配置中获取传入的req和res const { req, res } = response.config; const baseCookieOptions = { req, res, maxAge: 60 * 60 * 24 * 7, // 7天有效期,可按需调整 path: "/", // 确保全站可访问该Cookie secure: process.env.NODE_ENV === "production", // 生产环境启用HTTPS传输 sameSite: "strict", // 防范CSRF攻击 }; if (token) { setCookie("TOKEN", token, baseCookieOptions); console.log("««««« token »»»»»", token); } if (refreshToken) { setCookie("REFRESHTOKEN", refreshToken, { ...baseCookieOptions, maxAge: 60 * 60 * 24 * 14, // 刷新Token设置更长有效期 }); console.log("««««« refreshToken »»»»»", refreshToken); } return response; }, (error) => Promise.reject(error), ); export { axiosUser, axiosLogin };
服务端调用时传入req/res
以Pages Router的API路由为例,调用axiosLogin时需传入req和res:
// pages/api/login.js import { axiosLogin } from "../../utils/axios"; export default async function handler(req, res) { try { // 将req、res传入axios配置 const response = await axiosLogin.post("/login", req.body, { req, res }); res.status(200).json(response.data); } catch (error) { res.status(error.response?.status || 500).json(error.response?.data || { message: "登录失败" }); } }
2. 客户端场景:完善Cookie配置
在客户端组件(需标记"use client")中调用时,无需传入req/res,但需确保Cookie配置正确:
// components/LoginForm.js "use client"; import { axiosLogin } from "../utils/axios"; const LoginForm = () => { const handleLogin = async () => { try { await axiosLogin.post("/login", { username: "test", password: "test" }); // 登录成功后Cookie已全局生效 } catch (err) { console.error("登录失败:", err); } }; return <button onClick={handleLogin}>登录</button>; }; export default LoginForm;
额外检查项
- 确认
withCredentials: true已正确设置:该配置用于请求时携带Cookie,不影响设置,但确保后续请求能带上Token - 生产环境必须启用
secure: true:仅HTTPS环境可设置带secure属性的Cookie,本地开发可忽略 - 避免在静态生成(SSG)页面中调用:静态页面无服务端上下文,无法处理Cookie操作
内容的提问来源于stack exchange,提问作者Chu Phong
相关产品推荐
相关产品推荐

