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

React+Fastify登录授权异常:前端SessionID不一致问题求助

问题描述

我用fastify-session实现了仅登录用户可访问的Fastify路由,通过VS Code的Thunder Client测试时功能正常,登录后SessionID保持一致。但用React前端发起fetch请求时,每次请求的SessionID都不一样。

登录代码

login: async (username: string, password: string) => {
      try {
        let headersList = {
          Accept: "*/*",
          "Content-Type": "application/json",
        };

        let bodyContent = JSON.stringify({
          username: username,
          password: password,
        });

        let response = await fetch("http://127.0.0.1:1338/user/login", {
          method: "POST",
          body: bodyContent,
          headers: headersList,
          credentials: 'include'
        });

        let data = await response.json();
        console.log(data);
        console.log("cookie: ", response.headers.getSetCookie());

        if (data.user) {
          Cookies.set("session", JSON.stringify(data.user));
          console.log("data: ", Cookies.get('session'))
          console.log(data);
          set({ user: data.user, error: null, isAuthenticated: true });
        } else {
          console.log(
            "Error signing in:",
            data.error
          );
          alert(data.error);
          set({ user: null, error: data.error, isAuthenticated: false });
        }
      } catch (error) {
        console.log("Error:", error);
        set({ user: null, error, isAuthenticated: false });
      }
    }

GET请求代码

const getUsers = async (page: number) => {
  const baseUrl = "http://127.0.0.1:1338/user"; 
  const queryParams = new URLSearchParams();
  queryParams.append("page", `${page}`);
  const apiUrl = `${baseUrl}?${queryParams.toString()}`;
  try {
    let response = await fetch(apiUrl, {
      method: "GET",
      headers: {
        "Content-Type": "application/json",
      },
      credentials: "include",
    });
    console.log(await response.json());
  } catch (error) {
    console.error("Fetch error:", error);
  }
};

export default getUsers;

我尝试调整过服务端的SameSite属性,但因服务端测试正常,认为问题不在服务端。已设置credentials: 'include',但仍无法让前端请求保持相同的SessionID,请问该如何解决?


解决方案

从现象和代码来看,问题核心是跨场景下Session Cookie的传递规则不匹配,以下是具体解决步骤:

  1. 强制服务端CORS配置允许凭证
    Fastify必须明确指定前端域名并开启凭证支持,不能用*作为origin:

    fastify.register(require('@fastify/cors'), {
      origin: 'http://localhost:3000', // 替换为你的React前端实际地址
      credentials: true // 关键:允许请求携带Cookie
    })
    

    浏览器会拒绝在origin为*时携带Cookie,这是跨域安全规则的要求。

  2. 修正服务端Session的Cookie参数
    确保fastify-session的Cookie配置适配跨域场景:

    fastify.register(require('@fastify/session'), {
      secret: 'your-strong-secret-key',
      cookie: {
        path: '/',
        httpOnly: true, // 安全设置,禁止前端JS读取Session Cookie
        secure: process.env.NODE_ENV === 'production', // 生产环境必须开启(HTTPS)
        sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
        maxAge: 86400000 // 会话有效期,按需调整
      }
    })
    
    • 本地开发时用sameSite: 'lax'即可,无需HTTPS;生产环境跨域名时,sameSite设为'none'必须搭配secure: true。
    • 检查domain参数:如果前端和服务端是子域名关系,需要设置domain: '.yourdomain.com',但本地开发(IP/localhost)不需要。
  3. 验证浏览器Cookie的存储与携带
    打开Chrome DevTools:

    • 进入Application > Cookies > http://127.0.0.1:1338,确认是否存在服务端设置的Session Cookie(默认名为sessionId)。
    • 发起GET请求时,查看Network > 请求头,确认Cookie字段包含该SessionID。
      如果Cookie存在但未携带,检查credentials: 'include'是否在所有请求中正确设置(你的代码已设置,可确认拼写);如果Cookie不存在,说明Set-Cookie头被浏览器拦截,检查其参数是否违反安全规则。
  4. 移除前端手动存储的Session Cookie
    代码中Cookies.set("session", ...)是前端自定义的Cookie,和服务端的Session机制无关,反而容易混淆排查。建议删除这部分代码,完全依赖服务端的Session Cookie维持登录状态。


内容的提问来源于stack exchange,提问作者MFS Craft

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 14:20:35