NextJS生产环境中NextResponse.redirect不触发问题求助
问题分析
你的核心问题是生产环境下登录成功设置Cookie后,客户端跳转被middleware拦截,延迟一段时间才恢复正常。这是因为middleware中错误地从响应对象(res)读取Cookie,而非从请求对象(req)读取,导致middleware无法识别客户端刚设置的Cookie,进而错误触发重定向逻辑。此外,客户端路由跳转的时机可能早于Cookie生效的时机,也会加剧这个问题。
解决方案
1. 修复middleware的Cookie读取逻辑
原代码中getCookie("token", { req, res })会优先读取响应对象的Cookie,但响应对象是新创建的NextResponse.next(),不存在登录后设置的token。正确的做法是仅从请求对象(req)读取客户端发送的Cookie:
import { getCookie } from "cookies-next"; import type { NextRequest } from "next/server"; import { NextResponse } from "next/server"; export const config = { matcher: "/((?!api|_next/static|_next/image|assets|favicon.ico|verify-email).*)", }; export async function middleware(req: NextRequest) { // 仅从请求对象读取Cookie,这是客户端实际发送的凭证 const token = getCookie("token", { req }); const isAuthRoute = req.nextUrl.pathname === "/auth"; if (!token && !isAuthRoute) { return NextResponse.redirect(new URL("/auth", req.url)); } if (token && isAuthRoute) { return NextResponse.redirect(new URL("/projects", req.url)); } return NextResponse.next(); }
2. 优化客户端Cookie设置与跳转逻辑
如果修复middleware后问题仍存在,建议将Cookie设置逻辑移至API路由(更符合安全规范,同时确保Cookie立即生效),再执行跳转:
步骤1:创建登录API路由
// app/api/login/route.ts import { NextResponse } from "next/server"; export async function POST(request: Request) { try { const { phone, password } = await request.json(); // 调用后端验证接口获取token const authResponse = await fetch(process.env.AUTH_API_URL!, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ phone, password }), }); if (!authResponse.ok) throw new Error("登录验证失败"); const { token } = await authResponse.json(); // 由API路由设置Cookie(安全建议:开启httpOnly、secure) const response = NextResponse.json({ success: true }); response.cookies.set({ name: "token", value: token, httpOnly: true, secure: process.env.NODE_ENV === "production", sameSite: "strict", path: "/", maxAge: 86400, // 设置过期时间 }); return response; } catch (error) { return NextResponse.json({ error: (error as Error).message }, { status: 401 }); } }
步骤2:更新客户端登录逻辑
"use client"; import { useMutation } from "@tanstack/react-query"; import { useRouter } from "next/navigation"; import { useState } from "react"; export default function AuthPage() { const [phone, setPhone] = useState(""); const [password, setPassword] = useState(""); const router = useRouter(); const loginMutation = useMutation({ mutationFn: async () => { const res = await fetch("/api/login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ phone, password }), }); if (!res.ok) throw new Error("登录失败"); return res.json(); }, onSuccess: () => { // 跳转前强制刷新路由,确保middleware读取最新Cookie router.refresh(); router.push("/projects"); }, onError: (error) => { alert(error.message); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); loginMutation.mutate(); }; return ( <form onSubmit={handleSubmit}> <input type="text" value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="手机号" required /> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} placeholder="密码" required /> <button type="submit" disabled={loginMutation.isPending}> 登录 </button> </form> ); }
3. 极端场景下的兜底方案
如果上述方案仍有问题,可改用页面刷新式跳转(强制发起新HTTP请求,确保Cookie被携带):
// 在onSuccess中替换router.push为: window.location.href = "/projects";
这种方式会触发页面刷新,虽然体验略差,但能确保middleware读取到最新的Cookie。
内容的提问来源于stack exchange,提问作者Arad
相关产品推荐
相关产品推荐

