Я столкнулся с очень странной проблемой, которая сохраняется даже после нескольких часов устранения неполадок.
Прежде всего, мой интерфейс работает на 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 может произойти одно из следующего:
Я пробовал следующее: разрешение соединений для всех запросов OPTIONS в index.js, но это не решило мою проблему. Кроме того, если это имеет значение, все работает очень гладко, когда я запускаю свой бэкэнд на http://localhost:8800 и интерфейс на http://localhost:3000 без каких-либо проблем с CORS (очевидно, тогда источником, определенным в CORS, был localhost: 3000).
Я действительно застрял и хочу запустить сайт через день или два. Это последний шаг, поскольку, не имея возможности обновлять пользовательские изменения в базе данных, я упускаю самую важную функцию. Я вообще буду рад любому совету! Поскольку это мой первый полнофункциональный проект, если у вас есть соответствующие советы о том, как управлять различными целями или если какой-то код можно написать более чистым способом, я тоже буду очень признателен! Спасибо!!
🤔 А знаете ли вы, что...
React предоставляет жизненные циклы компонентов для управления состоянием и поведением.
Хорошо, ребята, я не уверен, что я сделал, но теперь это работает.
Вот что находится в моем 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 для запроса всех опций, помогут.