【问题标题】:Cookie not set in request with NodeJS and NextJSCookie 未在 NodeJS 和 NextJS 的请求中设置
【发布时间】:2022-01-23 18:28:57
【问题描述】:

我正在使用 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


    【解决方案1】:

    SAMESITE 无

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

    本地 PC 选项

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

    • 域=.somealias.com
    • 路径=/
    • SameSite=strict
    • 仅 HTTP

    已部署的选项

    当您部署到适当的环境时,还要使用 SSL 并设置 cookie 选项 Secure。最重要的是,这两个域必须满足共享同一个基域的托管先决条件,例如:

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

    类似的资源

    这个Curity code example 使用本地开发域和相同的站点 cookie 设置,类似于我在上面使用的设置,比较起来可能有用。

    【讨论】:

    • 感谢您的回复!不幸的是,这似乎也不起作用。在提出问题之前,我已经分别致电 somealias.com:3000 和 3001,我认为这里的问题是 somealias.com:3000 和 3001 被视为 2 个独立的域,因为它们的端口不同。
    • 即使端口不同,它们也是同一个域 - Curity 示例将端口 80 用于 www.example.com,将端口 3000 用于 api.example.com。也许尝试使用这样的子域。在生产中,两者都需要在端口 443 上运行,因此您需要设计子域。
    【解决方案2】:

    cookies 必须直接从浏览器发送到服务器,而当您使用 nextJs 时,情况并非如此。因为当您访问您的应用程序时,next js 将在服务器端呈现您的页面,然后请求将从 nextjs 服务器发送到您的 nodejs 服务器,因此浏览器会将 cookie 发送到 nextjs 服务器而不是您的 nodejs 服务器。 解决方案是将 cookie 从 nextjs 服务器手动发送到 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
          }
        }
    }
    

    【讨论】:

      【解决方案3】:

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

      或者,您可以使用res.cookie 方法而无需额外的cookie 包,如下所示:

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

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

      【讨论】:

      • 对不起,我忘了说明我也试过了,没用:(
      • @ddolce 您如何从 Next.js 应用程序向您的 Node.js 服务器发出请求?
      【解决方案4】:

      既然您说“我能够在响应中观察到 Set-Cookie 标头”,我相信您的 node.js 设置正确。

      当你从 node js 得到响应时,你需要设置 cookie,这可以通过 npm 包轻松完成。我会用js-cookie演示:

       import Cookies from "js-cookie";
      

      您编写一个可重用的函数来设置 cookie:

      // what ever your project returns 
      setSession(authResult) {
          //converting everything to miliseconds
          const expiresAt =
            JSON.stringify(authResult.expiresIn * 1000) + new Date().getTime();
          // I just put  properties. I dont know how project sets
          Cookies.set("user", authResult.idTokenPayload);
          Cookies.set("jwt", authResult.idToken);
          Cookies.set("expiresAt", expiresAt);
        }
      

      每次您提出请求时,您都必须设置标头。您必须根据您是在浏览器上还是在服务器上来检索 cookie。因此,如果您在服务器上,则必须编写一个函数。由于我演示了如何使用js-cookies 设置cookie,您可以在浏览器上轻松获取cookie。如果你在服务器上,这个可重用的函数来检索 cookie:

      // cookieKey: I set three "user", "jwt","expiresAt"
      export const getCookieFromReq = (req, cookieKey) => {
        console.log("req.headers", req.headers);
        // cookies are attached to the req.header.cookie. 
        const cookie = req.headers.cookie
          .split(";")
          .find((c) => c.trim().startsWith(`${cookieKey}=`));
      
        if (!cookie) return undefined;
        return cookie.split("=")[1];
      };
      

      现在你必须编写一个函数来设置标题:

      import Cookies from "js-cookie";
      import { getCookieFromReq } from "./directoryOf";
      
      export const setAuthHeader = (req) => {
        const token = req ? getCookieFromReq(req, "jwt") : Cookies.getJSON("jwt");
      
        if (token) {
          return {
            headers: { authorization: `Bearer ${token}` },
          };
        }
        return undefined;
      };
      

      现在当你提出请求时,你必须使用这个setAuthHeader。例如:

       await axiosInstance
          .post("/blogs", blogData, setAuthHeader())
          .then((response) => response.data)
          .catch((error) => rejectPromise(error));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-12-21
        • 2015-12-21
        • 1970-01-01
        • 1970-01-01
        • 2019-11-10
        • 1970-01-01
        • 2014-12-16
        • 2017-12-04
        相关资源
        最近更新 更多