Nextjs 14 中未通过部署在 Vercel 上的 Express Api 设置 Cookie

问题描述 投票:0回答:1

最近我部署了节点/express api 和客户端(Nextjs 14.1.0)来 vercel 除了 cookie 之外一切都工作正常。在某些情况下,我会收到 cookie,但它们只是临时的,当我刷新页面时,所有内容都消失了,而在其他情况下,我会收到有关域的警告(如下)。

“通过 Set-Cookie 设置 cookie 的尝试被阻止,因为其域属性无效”

即使我在cookie中设置了域名,如下所示,但仍然没有成功

res.cookie("refreshToken", refreshToken, {
    maxAge: 15 * 24 * 60 * 60 * 1000,
    sameSite: "none",
    httpOnly: true,
    secure: true,
    partitioned: true,
    domain: ".mern-nextjs-ecommerce.vercel.app"
  });
  res.cookie("accessToken", accessToken, {
    maxAge: 15 * 24 * 60 * 60 * 1000,
    sameSite: "none",
    httpOnly: true,
    secure: true,
    partitioned: true,
domain: ".mern-nextjs-ecommerce.vercel.app"
  });

登录码

export const signIn = TryCatch(async (req, res, next) => {
  const { email, password } = req.body;

  const user = await User.findOne({ email });
  if (!user) return next(new ErrorHandler("Invalid credentials", 400));

  const isMatched = await user.comparePassword(password);
  if (!isMatched) return next(new ErrorHandler("Invalid credentials", 400));

  const accessToken = jwt.sign({ id: user._id }, config.JWT_SECRET, {
    expiresIn: "45m",
  });

  const refreshToken = jwt.sign({ id: user._id }, config.JWT_SECRET);

  if (!user.tokens) user.tokens = [refreshToken];
  else user.tokens.push(refreshToken);

  await user.save();

  res.cookie("refreshToken", refreshToken, {
    maxAge: 15 * 24 * 60 * 60 * 1000,
    sameSite: "none",
    httpOnly: true,
    secure: true,
    partitioned: true,
  });
  res.cookie("accessToken", accessToken, {
    maxAge: 15 * 24 * 60 * 60 * 1000,
    sameSite: "none",
    httpOnly: true,
    secure: true,
    partitioned: true,
  });

  res.json({
    success: true,
    profile: {
      id: user._id,
      email: user.email,
      name: user.username,
      verified: user.verified,
      avatar: user.avatar?.url,
      accessToken: accessToken,
    },
    accessToken,
    refreshToken,
  });
});

Cors 配置

app.use(
  cors({
    origin: [
      "https://mern-nextjs-ecommerce.vercel.app",
      config.ADMIN_CLIENT_URL,
      "http://localhost:3000",
    ],
    credentials: true,
    methods: ["GET", "POST", "PUT", "DELETE"],
    allowedHeaders: [
      "Content-Type",
      "Authorization",
      "Origin",
      "X-Requested-With",
      "Accept",
      "Set-Cookie",
      "Cookie",
    ],
  })
);

前端提交功能

const handleSignInSubmit = async (data: SignInInput) => {
    try {
      const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}auth/signin`, {
        method: "POST",
        credentials: "include", // This ensures cookies are sent with the request
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          email: data.email,
          password: data.password,
        }),
      });

      const resData = await res.json();

       toast.success(resData.message || "Logged In !");
    } catch (error) {
      toast.error("An error occurred");
    }
  };

中间件.ts

import { NextRequest, NextResponse } from "next/server";

export async function middleware(request: NextRequest) {
  const accessToken = request.cookies.get("accessToken")?.value;
  const refreshToken = request.cookies.get("refreshToken")?.value;

  console.log("accessToken: ", accessToken);
  console.log("refreshToken: ", refreshToken);

  const response = NextResponse.next();

  if (!accessToken || !refreshToken) return response;

  const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}auth/me`, {
    method: "GET",
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
    credentials: "include",
  });
  if (res.status === 401) {
    try {
      const res = await fetch(
        `${process.env.NEXT_PUBLIC_API_URL}auth/refresh-token`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            refreshToken: refreshToken,
          }),
          credentials: "include",
        }
      );

      const data = await res.json();
      if (data.success) {
        const response = NextResponse.redirect(request.url);
        response.cookies.set("accessToken", data.tokens.access, {
          httpOnly: true,
          sameSite: "lax",
        });
        response.cookies.set("refreshToken", data.tokens.refresh, {
          httpOnly: true,
          sameSite: "lax",
        });
        return response;
      }
    } catch (error) {
      console.log("An error occurred11111: ", error);
    }
  }

  return response;
}
express cookies nextjs14
1个回答
0
投票

我建议您根据 NextRequest 的主机名动态设置域。如果您在 Vercel 上进行部署,这将帮助您更轻松地处理预览链接和开发/生产部署

© www.soinside.com 2019 - 2024. All rights reserved.