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

NextJS路由全局变量无法跨请求持久化:POST存token后GET取不到

问题根源分析

你用全局变量access_token和refresh_token存储令牌的方式本质错误,原因在于:
Next.js的Route Handler是无状态、请求隔离的——每次请求都会重新执行整个模块代码,且在多实例部署环境(比如Vercel的无服务器架构)中,不同请求可能分配到不同的服务器实例上。POST请求设置的全局变量仅在当前请求的临时执行上下文里有效,后续GET请求会进入全新的执行环境,全局变量会被重置为初始的null值。

解决方案

方案1:用Cookie存储(适合单用户/无多用户区分的场景)

将令牌绑定到用户的Cookie中,确保状态可跨请求持久化,同时通过httpOnly属性提升安全性:

import { NextResponse } from "next/server";

const CLIENT_ID = process.env.CLIENT_ID;
const CLIENT_SECRET = process.env.CLIENT_SECRET;
const BASE_URI = process.env.BASE_URI;

export async function POST(req) {
  const tokens = await req.json();
  const response = NextResponse.redirect(BASE_URI + "home/");

  // 将令牌存入Cookie,根据实际令牌有效期调整maxAge
  response.cookies.set("access_token", tokens.access_token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    maxAge: 3600, // 1小时
    path: "/",
  });
  response.cookies.set("refresh_token", tokens.refresh_token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    maxAge: 60 * 60 * 24 * 7, // 7天
    path: "/",
  });

  console.log(tokens);
  return response;
}

export async function GET(req) {
  const access_token = req.cookies.get("access_token")?.value;

  if (!access_token) {
    console.log("Authorization Error");
    return new NextResponse("Authorization Error", { status: 401 });
  } else {
    return NextResponse.json({ access_token });
  }
}

方案2:用数据库存储(适合多用户场景)

如果你的应用需要区分不同用户的令牌,需将令牌与用户身份关联后存入数据库,示例用Prisma ORM+NextAuth做用户认证:

import { NextResponse } from "next/server";
import prisma from "@/lib/prisma"; // 你的Prisma客户端实例
import { getServerSession } from "next-auth/next";
import authOptions from "@/lib/authOptions"; // 你的NextAuth配置

export async function POST(req) {
  const tokens = await req.json();
  const session = await getServerSession(authOptions);

  if (!session?.user) {
    return new NextResponse("Unauthorized", { status: 401 });
  }

  // 将令牌关联到用户存入数据库
  await prisma.user.update({
    where: { id: session.user.id },
    data: {
      accessToken: tokens.access_token,
      refreshToken: tokens.refresh_token,
    },
  });

  return NextResponse.redirect(BASE_URI + "home/");
}

export async function GET(req) {
  const session = await getServerSession(authOptions);

  if (!session?.user) {
    return new NextResponse("Unauthorized", { status: 401 });
  }

  const user = await prisma.user.findUnique({
    where: { id: session.user.id },
    select: { accessToken: true },
  });

  if (!user?.accessToken) {
    console.log("Authorization Error");
    return new NextResponse("Authorization Error", { status: 401 });
  } else {
    return NextResponse.json({ access_token: user.accessToken });
  }
}
关键注意事项
  • 绝对不要用全局变量存储请求相关的状态,Next.js无服务器架构下全局变量不具备持久化能力
  • 敏感令牌需加密存储,生产环境务必开启secure Cookie属性(仅HTTPS传输)
  • 多用户场景必须关联用户身份存储令牌,避免不同用户的令牌混淆

内容的提问来源于stack exchange,提问作者Alexander Williams

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:54:54