Reactjs cient没有从express服务器接收cookies

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

我在不同的服务器上运行我的项目,后端在渲染上,前端在 vercel 上。然而,我只是在部署时遇到这个错误,这意味着 cookie 要么没有在客户端正确设置,要么没有被正确检索。

我已经检查了 cors 和 axios 中的凭据。我还检查了 res.cookies 中的“withCredentials”以及其他参数是否设置为 true。控制台中没有错误。登录显示成功。它只是不接收 cookie,因此无法重定向到主页。我不知道还能做什么。

这是express服务器上的登录功能

const Login = async (req, res, next) => {
    try {
        const { email, password } = req.body
        if (!email || !password) {
            return res.json({ message: "All fields required" })
        }
        const user = await User.findOne({ email })
        if (!user) {
            return res.json({ message: "Incorrect email or password" })
        }
        const auth = await bcrypt.compare(password, user.password)
        if (!auth) {
            return res.json({ message: "Incorrect email or password" })
        }

        const token = createSecretToken(user._id);

        
        res.cookie("token", token, {
            withCredentials: true,
            httpOnly: false,
        });
        res.status(201).json({ message: "User logged in successfully", success: true });
        next()
    } catch (error) {
        console.log(error)
    }
}

这是服务器上的index.js

const express = require('express');
const mongoose = require('mongoose');
const bcrypt = require('bcrypt')
const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser")
const path = require('path')
const cors = require('cors')
require('dotenv').config();

const app = express();

const classRoutes = require('./routes/courseRoutes')
const authRoute = require("./routes/AuthRoutes");

const PORT = process.env.PORT || 4000;

mongoose.connection.on('connected', () => {
    console.log('Connected to MongoDB Atlas');
});

app.use((req, res, next) => {
    res.header("Access-Control-Allow-Origin", "https://divcourses.vercel.app");
    res.header("Access-Control-Allow-Credentials", "true");
    res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
    next();
});

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser());

app.use('/api', classRoutes)
app.use('/api', authRoute);
app.use((req, res, next) => {
    console.log(`${req.method} ${req.url}`);
    next();
});
const atlasConnectionUri = process.env.MONGODB_URL;
mongoose.connect(atlasConnectionUri, {
    dbName: 'subjects'
});

app.get('/', async (req, res) => {
    try {
        res.status(200).json({ message: "Welcome to Home Route 🏠" })
    } catch (error) {
        res.status(500).json({ message: "Error in Home Route ❌" })
    }
});

app.listen(PORT, () => {
    console.log(`Server is Running at ${PORT}`);
});

这是reactjs上的登录路线

import React, { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import axios from "axios";
import { ToastContainer, toast } from "react-toastify";

const Login = () => {

    const navigate = useNavigate()
    const [inputValue, setInputValue] = useState({
        email: "",
        password: ""
    })

    const { email, password } = inputValue

    const handleOnChange = (e) => {
        const { name, value } = e.target
        setInputValue({
            ...inputValue,
            [name]: value
        })
    }

    const handleError = (err) =>
        toast.error(err, {
            position: "bottom-left",
        });
    const handleSuccess = (msg) =>
        toast.success(msg, {
            position: "bottom-left",
        });


    const handleSubmit = async (e) => {
        e.preventDefault()
        try {
            // `${baseURL}/login`
            const { data } = await axios.post(
                "https://mern-deploy-practice.onrender.com/api/login",
                { ...inputValue },
                { withCredentials: true }
            )
            console.log(data);
            const { success, message } = data;
            if (success) {
                handleSuccess(message);
                setTimeout(() => {
                    navigate("/");
                }, 1000);
            } else {
                handleError(message);
            }
        } catch (error) {
            console.log(error);
        }
        setInputValue({
            ...inputValue,
            email: "",
            password: "",
        });
    };

这是用户成功登录后应重定向到的主页路由

import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useCookies } from "react-cookie";
import { Link } from "react-router-dom";
import axios from "axios";
import { ToastContainer, toast } from "react-toastify";


const Home = () => {
    const [cookies, setCookies, removeCookie] = useCookies(['token']);
    const [username, setUsername] = useState('')
    const navigate = useNavigate()

    useEffect(() => {
                const verifyCookie = async () => {
            try {
                const response = await axios.post(
                    "https://mern-deploy-practice.onrender.com/api",
                    {},
                    { withCredentials: true }
                );

                if (response && response.data) {
                    const { status, user } = response.data;
                    setUsername(user)
                    setCookies('token', cookies.token)
                    const greeted = localStorage.getItem('greeted');
                    if (!greeted) {
                        toast(`Hello ${user}`, { position: "top-right" });
                        localStorage.setItem('greeted', 'true');
                    }
                } else {
                    console.error(error)
                    removeCookie("token");
                    navigate('/login');
                }
            } catch (error) {
                console.error("Error verifying cookie:", error);
                removeCookie("token");
                navigate('/login'); ``
            }

            if (!cookies.token) {
                navigate("/login");
                return;
            }
        };

        verifyCookie();
    }, [cookies, navigate, setCookies, removeCookie]);

    const Logout = () => {
        removeCookie("token");
        navigate("/signup");
    };

这些是网络选项卡中的响应标头
enter image description here

这些是请求标头
enter image description here

reactjs express cookies deployment setcookie
1个回答
0
投票

这是由于对 cookie 跨域功能的混淆所致。

看起来后端服务器位于“https://mern-deploy-practice.onrender.com/api”,因此当设置 cookie 时,浏览器会针对 that 域存储该 cookie。

前端代码位于Vercel域上。从根本上来说,它无法读取通过对外部域的调用设置的 cookie,因为该 cookie 属于该外部域。不过,您可以调用该外部域,当您隐式调用时,浏览器将在幕后发送相关 cookie。但您只能读取/检查 JS 中由 Vercel 域“拥有”的 cookie。

如果这是可能的,那将是一场灾难,因为任何网站都可能窃取另一个网站拥有的 cookie!因此,有一个基本原则,即 JS 只能读取在 JS 本身提供服务的同一域上设置的 cookie。

这里的解决方案看起来很简单。甚至不要尝试在 JS 中检查 cookie。除非我缺少上下文,否则似乎没有必要。您知道他们已通过 auth HTTP req 成功登录。您可以放心,(即使您无法检查它们)浏览器会将 cookie 发送到由该域上的后端服务设置的外部域。

如果您出于某种原因需要某些数据,通常服务器会在某个 API 端点上返回这些数据,您可以调用它来获取它。

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