Заблокировано политикой CORS, несмотря на наличие доменного имени в файле на стороне сервера

Я столкнулся с очень странной проблемой, которая сохраняется даже после нескольких часов устранения неполадок.

история проекта

Прежде всего, мой интерфейс работает на React+Vite (но на самом деле я не использовал ничего, связанного с Vite), размещен на Vercel, скажем, https://mywebsite.ca

Мой бэкэнд работает на Express и Node, а также размещен на Vercel по адресу https://backend.vercel.app

Моя база данных MySQL размещена на AWS RDS.

Проблема

Проблема в том, что все на странице входа или регистрации работает (иногда пишет, что это не ошибка сервера, но это очень редко). На этом этапе я не столкнулся с какой-либо проблемой CORS. Однако в тот момент, когда пользователь входит в систему (что направляет меня на https://mywebsite.ca/course-selection), я сталкиваюсь с проблемой CORS.

Я почти уверен, что все мои CORS четко определены, как вы можете видеть в моем index.js здесь:

import express from "express"
import cors from "cors"
import userRoutes from "./routes/users.js"
import authRoutes from "./routes/auth.js"
import courseChangeRoutes from "./routes/courseChange.js"
import cookieParser from "cookie-parser";


const app = express();
app.use(express.json());
app.use(cookieParser());

app.use(
    cors({
      origin: 'https://www.mywebsite.ca',
      methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'],
      credentials: true,
    })
);

app.use((req, res, next) => {
  res.header("Access-Control-Allow-Credentials", true);
  next();
});

app.use("/backend/users", userRoutes);
app.use("/backend/auth", authRoutes);
app.use("/backend/courseChange", courseChangeRoutes);

Я даже добавил OPTIONS, потому что провел небольшое исследование и обнаружил, что иногда предполетные запросы выполняются с использованием OPTIONS. Однако проблема сохраняется, и я все еще часто получаю: Доступ к XMLHttpRequest по адресу «https://backend.vercel.app/backend/courseChange/» из источника «https://www.mywebsite.ca» заблокирован политикой CORS: нет «Access-Control-Allow-Origin». заголовок присутствует в запрошенном ресурсе. Затем последовало с Не удалось загрузить ресурс: net::ERR_FAILED.

Благодаря мониторингу вкладки «Сети» было обнаружено множество неудачных запросов, которые выглядели следующим образом:

URL-адрес запроса: https://backend.vercel.app/backend/courseChange/ Политика рефералов: строгое происхождение при перекрестном происхождении с JSON полезной нагрузки в правильном формате

ИЛИ URL-адрес запроса: https://backend.vercel.app/backend/courseChange/ Метод запроса: ПАРАМЕТРЫ Код состояния: 500 - внутренняя ошибка сервера Политика рефералов: строгое происхождение при перекрестном происхождении

Другие соответствующие файлы, которые могут быть полезны для устранения неполадок.

/operation/courseChange.js: (серверная часть)


export const courseChange = async (req, res) => {
    const { userId, courses_ids, term } = req.body;

    if (!userId || !Array.isArray(courses_ids) || !term) {
        return res.status(400).send('Invalid input');
    }

    const maxCourses = 15; 

    try {
        // Clear existing courses for the specified term
        let clearQuery = 'UPDATE users SET ';
        for (let i = 1; i <= maxCourses; i++) {
            clearQuery += `${term}Course${i} = NULL, `;
        }
        clearQuery = clearQuery.slice(0, -2) + ' WHERE id = ?';
        console.info('Clear Query:', clearQuery, [userId]);
        await db.execute(clearQuery, [userId]);

        // Construct the update query for new courses
        let updateQuery = 'UPDATE users SET ';
        const updateValues = [];
        if (courses_ids.length > 0) {
            courses_ids.forEach((courseId, index) => {
                updateQuery += `${term}Course${index + 1} = ?, `;
                updateValues.push(courseId);
            });
            updateQuery = updateQuery.slice(0, -2);
            updateQuery += ' WHERE id = ?';
            updateValues.push(userId);


            console.info('Update Query:', updateQuery, updateValues);
            await db.execute(updateQuery, updateValues);
            res.status(200).send('Courses updated successfully');
            }

    } catch (error) {
        console.error('Error updating courses:', error);
        res.status(500).send('Error updating courses: ' + error.message);
    }
    
};

/pages/course-selection.jsx: (интерфейс)

import { useState, useEffect } from 'react';
import LeftMenu from '/src/components/leftMenu';
import Calendar from '/src/components/calendar';
import Nav from '/src/components/nav';
import Selection from '/src/components/selections';
import fallJSON from '/src/assets/fall_2024_0626.json';
import winterJSON from '/src/assets/winter_2025_0626.json';
import axios from 'axios'

axios.defaults.withCredentials = true;


export default function Courses() {

    const [fallCourses, setFallCourses] = useState([]);
    const [winterCourses, setWinterCourses] = useState([]);
    const [fallData, setFallData] = useState(fallJSON);
    const [winterData, setWinterData] = useState(winterJSON);
    const [err, setError] = useState(null);

    const updateFallCourses = async (courses_ids) => {
        // Prepare for Calendar Rendering
        const courses = courses_ids.flatMap(course => fallData[course].slice(2));
        setFallCourses(courses);
        // Send data to backend
        const user = JSON.parse(localStorage.getItem('user'));
        const userId = user ? user.id : null;
        const term = "fall"
        try {
            await axios.post('https://backend.vercel.app/backend/courseChange/', {
                userId,
                courses_ids,
                term,
            }, {
                headers: {
                    'Access-Control-Allow-Origin': '*',
                    'Content-Type': 'application/json',
                }
            });
            console.info('Courses updated successfully');
        } catch (err) {
            const errorMessage = err.response?.data?.message || "An unexpected error occurred";
            setError(errorMessage);
        }

    };

// There's also const updateWinterCourses right here that basically is the same code

Непредсказуемое поведение

Наконец, что-то неожиданное: при вызове функции updateFallCourses может произойти одно из следующего:

  1. Ошибки CORS и ERR выводятся в консоль, ничего не происходит.
  2. Ошибки CORS и ERR не появляются. Я получаю сообщение «Курсы обновлены успешно», и база данных обновлена.
  3. Как и 2, ошибок нет, сообщение об успехе, но база данных НЕ обновляется.

Я пробовал следующее: разрешение соединений для всех запросов OPTIONS в index.js, но это не решило мою проблему. Кроме того, если это имеет значение, все работает очень гладко, когда я запускаю свой бэкэнд на http://localhost:8800 и интерфейс на http://localhost:3000 без каких-либо проблем с CORS (очевидно, тогда источником, определенным в CORS, был localhost: 3000).

Я действительно застрял и хочу запустить сайт через день или два. Это последний шаг, поскольку, не имея возможности обновлять пользовательские изменения в базе данных, я упускаю самую важную функцию. Я вообще буду рад любому совету! Поскольку это мой первый полнофункциональный проект, если у вас есть соответствующие советы о том, как управлять различными целями или если какой-то код можно написать более чистым способом, я тоже буду очень признателен! Спасибо!!

🤔 А знаете ли вы, что...
React предоставляет жизненные циклы компонентов для управления состоянием и поведением.


74
1

Ответ:

Решено

Хорошо, ребята, я не уверен, что я сделал, но теперь это работает.

Вот что находится в моем index.js

const app = express();

app.use(express.json());
app.use(cookieParser());

app.use(cors({
  origin: ["https://www.mywebsite.ca", "http://localhost:3000"], // Allow requests from this origin
  methods: ['GET', 'POST', 'PUT', 'DELETE'], // Allow these HTTP methods
  allowedHeaders: ['Content-Type', 'Authorization'], // Allow these headers
  exposedHeaders: ['Authorization'], // Headers that clients are allowed to access
  credentials: true, // Allow sending cookies along with requests
  maxAge: 86400, // Cache preflight request for 1 day (in seconds)
}));

app.options('*', (req, res) => {
  res.sendStatus(200);
})

Кажется, что maxAge и строка, возвращающая 200 для запроса всех опций, помогут.