NodeJS 和 NextJS 的请求中未设置 Cookie

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

我正在开发一个带有 Node + Express 后端和 NextJS 前端(独立服务器)的全栈应用程序,但在请求浏览器附加作为节点服务器响应标头的一部分发布的 cookie 时遇到问题。设置如下:

  1. Node 服务器在 localhost:3000 上运行,NextJs 服务器在 localhost:3001 上运行。
  2. 我已经在 etc/hosts 中设置了别名,将 someAlias.com 路由到 127.0.0.1。

使用前端 UI(端口 3001),我可以通过 JsHttp 的 cookie 模块从后端(端口 3000)使用以下代码来出售 cookie:

import { serialize } from 'cookie';
...
const cookie = serialize(TOKEN_NAME, TOKEN_VAL, {
  httpOnly: true,
  sameSite: 'none',
});

我能够观察到响应中的

Set-Cookie
标头。

但是,在随后的请求中,我没有看到附加cookie。我尝试摆弄上面的 cookie 序列化参数,但没有成功:

以下是我尝试过的论点:

  • domain: ['.someAlias.com:3000', '.someAlias.com:3001']
  • path: '/'
  • domain: '.someAlias.com'

我有一种感觉,这可能只是由于前端和后端服务器端口不同,但所有请求都是在客户端发起的,前往 localhost:3000 (后端端口)。所以不确定我在这里可能做错了什么。

======更新=======

我又进行了一些实验,发现当我直接访问 URL 时,NextJs 会在服务器端渲染页面。当我在应用程序内的页面之间进行转换时,页面会在客户端呈现,并直接查询后端端口 3000。不幸的是,在这两种情况下我都没有看到任何 cookie 被设置......

javascript node.js cookies next.js setcookie
5个回答
2
投票

cookie 必须直接从浏览器发送到服务器,而使用 nextJs 时则不是这样。因为当您访问您的应用程序时,下一个js将在服务器端呈现您的页面,然后请求将从nextjs服务器发送到您的nodejs服务器,因此浏览器会将cookie发送到nextjs服务器而不是您的nodejs服务器。 解决方案是手动从 nextjs 服务器发送 cookie 到 nodejs 。 fetchApi 和 getServerSideProps 函数的示例:

export async function getServerSideProps(context){ 
  try{
       const res = await fetch(`your-api-endpoint`, {
          method: 'GET',
          credentials:'include',
          headers: {
             'Access-Control-Allow-Credentials': true,
             Cookie: context.req.headers.cookie
          },
    })
    const data = await res.json()
    if(!res.ok){
       throw data 
    }
    }catch(err){
       return console.log(err)
    }

    return {
      props: {
         data
      }
    }
}

1
投票

同一个站点没有

如果您使用

SameSite=none
,您还需要使用
Secure
,这意味着还必须使用 SSL。然后您会说您的 2 个服务器来自不相关的域,这可能不是您想要的,因为浏览器会主动删除 cookie。

本地电脑选项

首先在开发计算机上使用这些设置,并确保浏览器和 Ajax 调用中使用的所有 URL 使用 http://somealias.com:3000http://somealias.com:3001 而不是 localhost。然后 Cookie 将保留在开发计算机上。

  • 域名=.somealias.com
  • 路径=/
  • 同站点=严格
  • 仅 HTTP

部署选项

当您部署到适当的环境时,还要使用 SSL 并设置 cookie 选项

Secure
。最重要的是,两个域必须满足共享相同基域的托管先决条件,例如:

这可确保发出的 cookie 被视为第一方且位于同一站点,因此它们不会被删除。如果不满足先决条件,则您无法在代码中执行任何操作来解决问题。

类似资源

这个 Curity 代码示例 使用本地开发域和相同的站点 cookie 设置,与我上面使用的类似,可能有助于比较。


0
投票

您必须手动设置Cookies

  1. 在 Node js 中安装“cookie”
npm i cookie 
import User from "../../models/UserModel.js";
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import cookie from "cookie";

export const UserLoginController = async (req, res) => {
try {
 const { email, password } = await req.body;

 //checking user
 const user = await User.findOne({ email }).select("+password");
 if (!user) {
   throw new Error("User not Found");
 }
 console.log(user);

 //checking password
 const isValidPassword = await bcrypt.compare(password, user.password);
 if (!isValidPassword) throw new Error("Invalid password");

 if (user && isValidPassword) {
   const payload = {
     userId: user._id,
   };
   const token = jwt.sign(payload, process.env.SECRET);
   const cookies = cookie.serialize("token", token);
   return res.status(200).json({ message: "Login successful", cookies });
 }
} catch (error) {
 return res.status(401).json(error.message);
}
};
  1. 现在在Next js中安装react-cookies
npm i react-cookie 

您可以阅读有关 react-cookies

的更多信息
const LoginSubmitHandler = async (data: any) => {
    try {
      console.log(data);
      const res = await axios.post("http://localhost:5000/users/login", data);
      const cookies = res.data.cookies.split("=")[1];
      console.log(cookies);
      setCookies("token", cookies);

      toast.success(res.data.message);
    } catch (error: any) {
      console.log(error);
      toast.error(error.response.data);
    }
  };

这样您就可以手动设置cookie了


0
投票

根据我在 GitHub 上找到的这条评论,如果您将

sameSite
设置为
none
,则必须将
secure
设置为
true
;否则,浏览器将永远不会保存cookie。

不幸的是,

secure: true
不适用于
localhost
,因此解决方法是检查您的环境,并在本地工作时将
sameSite
设置为
lax
,将
secure
设置为
false

您的代码可能如下所示:

...
const ENVIRONMENT = process.env.NODE_ENV || "development";

const cookie = serialize(TOKEN_NAME, TOKEN_VAL, {
  httpOnly: true,
  secure: ENVIRONMENT === "production",
  sameSite: ENVIRONMENT === "production" ? "none" : "lax",
});
...

-1
投票

您应该使用 res.set Express 方法设置序列化 cookie。

或者,您可以使用 res.cookie 方法,无需额外的

cookie
包,如下所示:

res.cookie(TOKEN_NAME, TOKEN_VAL, {
  httpOnly: true,
  sameSite: 'none',
});

注意,您不必担心同一域上的不同端口,因为 cookie 不是按端口隔离的,而是仅按域隔离的。无论您使用哪个端口,cookie 都应该是可见的。

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