You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中间件无法获取已设置的access_token Cookie问题排查

问题:Next.js中间件无法获取已设置的Cookie

用户在localhost:3000/auth页面登录后,后端成功返回并在Cookie中设置了access_token,前端登录成功后重定向到/protected页面触发中间件,但中间件中始终获取不到Cookie(开发者工具能看到Cookie已存在)。


前端中间件代码(middleware.ts)

const protectedRoutes = ['/protected'];

export async function middleware(request: NextRequest) {
    const { cookies, nextUrl } = request;
    const test = request.cookies.get('access_token')
    console.log(request)
    if (!cookies) {
        return "prout"
    }
    const accessToken = cookies.get('access_token');

    const isProtected = protectedRoutes.includes(nextUrl.pathname);

    if (isProtected && !accessToken) {
        return NextResponse.redirect(new URL('/auth', request.url));
    }
    console.log(nextUrl.pathname)
    if (nextUrl.pathname === '/auth' && accessToken) {
        return NextResponse.redirect(new URL('/protected', request.url));
    }

    return NextResponse.next();
}

export const config = {
    matcher: ['/auth', '/protected'],
};

前端登录提交逻辑

const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setError("");
    try {
        const response = await loginUser(form);
        console.log(response)
        // setForm({ username: "", password: "" });
        router.push('/protected')
    } catch (error: any) {
        console.log(error)
        setError("Registration error: " + error.message);
    }
};

后端登录接口代码(Python/FastAPI)

async def login_user(db: AsyncSession, username: str, password: str):
    """
    check if correct credentials and return bearer token
    """
    user = await get_user_by_username(db, username)
    if not user or not verify_password(password, user.password):
        time.sleep(3)
        raise HTTPException(status_code=401, detail="Invalid credentials")
    access_token = create_access_token(
        {"sub": user.username}, 
        timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    )
    refresh_token = create_refresh_token(
        {"sub": user.username}, 
        expires_delta=timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
    )
    csrf_token = generate_csrf_token()
    response = JSONResponse(content={"message": "Login successful"})

    response.set_cookie(
        key="access_token",
        value=access_token,
        httponly=True,
        path='/',
        samesite='none',
        secure=True
        )
    response.set_cookie(
        key="refresh_token",
        value=refresh_token,
        path='/', # TODO /refresh
        httponly=True,
        samesite='none',
        secure=True
    )
    response.set_cookie(
        key="csrf_token",
        value=csrf_token,
        httponly=False,
        path='/',
        samesite='none',
        secure=True
    )
    return response

原因分析

问题核心出在Cookie的secure: true和samesite: none配置:

  1. secure: true限制:该配置要求Cookie只能通过HTTPS协议传输,但你当前使用的是localhost:3000(HTTP协议),浏览器不会把HTTPS专属的Cookie发送到HTTP站点,导致中间件获取不到。
  2. samesite: none的配套要求:当samesite设为none时,必须同时设置secure: true,但本地开发环境是HTTP,这直接导致Cookie无法被正确传递到中间件。

Next.js中间件运行在服务器端/边缘节点,它接收的是浏览器请求头里的Cookie,若浏览器因协议限制未携带Cookie,中间件自然拿不到。

解决方案

针对本地开发环境,修改后端Cookie配置:

  • 保留httponly: true和path: '/',调整samesite和secure参数:
    response.set_cookie(
        key="access_token",
        value=access_token,
        httponly=True,
        path='/',
        samesite='lax',  # 本地开发用lax或strict
        secure=False     # 本地HTTP环境设为false
    )
    
  • 生产环境再改回samesite: 'none'和secure: true,确保HTTPS环境下的跨域Cookie正常工作。

若需要模拟生产环境,也可以在本地启用HTTPS(比如用mkcert生成证书),这样就能保留secure: true配置,但操作相对繁琐。

内容的提问来源于stack exchange,提问作者El Pandario

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 08:28:12