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

跨域部署(Netlify+Heroku)下React+Node.js的Cookie存储问题

跨域部署下Cookie无法存储的问题解决

问题描述

将React前端部署在Netlify、Node.js后端部署在Heroku后,Cookie设置功能失效。此前两者同部署在Heroku时功能正常,但该方案无法支持前端从GitHub推送代码时自动部署。当前后端在Heroku、前端在Netlify,登录请求中服务器已正常发送Cookie,但浏览器未将其存入Cookie存储。

相关代码

后端index.js

const express = require("express");
const app = express();
const cookieParser = require("cookie-parser");
const authRoute = require("./routes/auth-route.js");

app.set("trust proxy",1);
// 跨域请求中间件
app.use(
  cors({
    credentials: true,
    origin: "https://myfrontend.com",
  })
);

// 解析请求中的Cookie
app.use(cookieParser({}));

// 解析请求体
app.use(express.json());

// 路由转发
app.use("/api/auth", authRoute);  

后端authRoute.js

const router = require("express").Router();
const {login} = require("../controllers/auth-controller");
router.post("/login", login);
module.exports = router;

后端auth-controller.js

const bcrypt = require("bcrypt");
const User = require("../models/User");
const generateJwt = require("../utils/generateJWT");
const login = async (req, res) => {
    try {
      // 根据邮箱查找用户
      const user = await User.findOne({ email: req.body.email });
      if (!user)
        return res.status(404).json({ success: false, message: "Email or Password Incorrect" });
    
      // 验证密码
      const validatePassword = await bcrypt.compare(req.body.password, user.password);
  
      if (!validatePassword)
        return res.status(404).json({ success: false, message: "Email or Password Incorrect" });
  
      // 剔除密码字段
      const { password, ...others } = user._doc;
      // 生成JWT
      const token = generateJwt(user._id);
  
      // 设置Cookie
      // 勾选rememberMe则Cookie有效期30天,否则为会话期
      if (req.body.rememberMe === true) {
        res.cookie("isLogged", true, {
          sameSite: "none",
          secure: true,
          domain: "app-frontend.netlify.app",
          maxAge: 2592000000, // 30天
        });
  
        res.cookie("authToken", token, {
          httpOnly: true,
          sameSite: "none",
          domain: "app-frontend.netlify.app",
          secure: true,
          maxAge: 2592000000, // 30天
        });
      } else {
        res.cookie("isLogged", true, {
          sameSite: "none",
          domain: "app-frontend.netlify.app",
          secure: true,
        });
  
        res.cookie("authToken", token, {
          httpOnly: true,
          sameSite: "none",
          domain: "app-frontend.netlify.app",
          secure: true,
        });
      }
      res.status(200).json({ success: true, user: others });
    } catch (err) {
      console.log(err);
      res.status(500).json({ success: false, message: err });
    }
  };

  module.exports = {login };

前端axiosConfig.js

import axios from "axios";
const axiosInstance = axios.create({
  withCredentials: true,
  baseURL: "https://app-backend.herokuapp.com/api/",
});

export default axiosInstance;

前端登录函数

import axios from "../../utils/axiosConfig";
const login = async () => {
  try {
    dispatch(setIsLoading(true));
    const data = {
      email: email.current.value,
      password: password.current.value,
      rememberMe: rememberMe.current.checked,
    };
    const res = await axios.post("auth/login", data);
    dispatch(setIsLoading(false));
    if (res.status === 200) {
      dispatch(setUser(res.data.user));
    }
  } catch (err) {
      dispatch(
        setIsError({
          status: true,
          message: err.response.data.message,
        })
      );
      dispatch(setIsLoading(false));   
  }
};

解决方案

1. 移除Cookie的domain配置

跨域场景下,浏览器会拒绝存储来自不同域名服务器设置的、指定为其他域名的Cookie。直接删除所有Cookie配置中的domain字段,让浏览器自动绑定Cookie到后端的Heroku域名:

修改auth-controller.js中的Cookie设置:

// 勾选rememberMe时的配置
res.cookie("isLogged", true, {
  sameSite: "none",
  secure: true,
  maxAge: 2592000000,
});

res.cookie("authToken", token, {
  httpOnly: true,
  sameSite: "none",
  secure: true,
  maxAge: 2592000000,
});

// 未勾选rememberMe时的配置
res.cookie("isLogged", true, {
  sameSite: "none",
  secure: true,
});

res.cookie("authToken", token, {
  httpOnly: true,
  sameSite: "none",
  secure: true,
});

2. 修正CORS的origin配置

确保index.js中CORS的origin与Netlify前端的实际域名完全一致,比如你的前端域名是https://app-frontend.netlify.app,则修改为:

app.use(
  cors({
    credentials: true,
    origin: "https://app-frontend.netlify.app",
  })
);

3. 确认代理信任设置

当前的app.set("trust proxy", 1)配置正确,Heroku使用反向代理,该设置能让Express正确识别请求的协议和客户端信息,保证secure Cookie正常生效。

4. 前端配置无需修改

你的Axios实例已经开启withCredentials: true,该配置会让前端请求自动携带Cookie,无需调整。

原理说明

跨域场景中,浏览器的同源策略禁止服务器为其他域名设置Cookie。删除domain字段后,Cookie会被绑定到后端的Heroku域名,当前端发送请求时,只要withCredentials开启,浏览器就会自动将该Cookie携带到后端,实现身份验证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 20:55:20