Как развернуть внешнее приложение React Router с бэкэндом NodeJS на Render

Я развернул свой проект на render.com, и мое приложение доступно по этой ссылке https://react-router-events-j6yu.onrender.com/

Однако когда я перехожу по URL-адресу с помощью /events, пользовательский интерфейс исчезает, и страница отображается следующим образом:

// 20240523233320
// https://react-router-events-j6yu.onrender.com/events/55b79b2e-902f-44b1-b292-08ab669b76c6

{
  "event": {
    "title": "Test again...",
    "image": "https://www.meydanfz.ae/wp-content/uploads/2021/10/Events-1024x576.png",
    "date": "2024-06-08",
    "description": "Test",
    "id": "55b79b2e-902f-44b1-b292-08ab669b76c6"
  }
}

Он отображает данные JSON вместо HTML.

Я связался со службой поддержки Render, и они сказали, что, возможно, это проблема приложения, а не проблема конкретного рендеринга.

Действительно, я создал «веб-сервис» при рендеринге для одновременного размещения как моего серверного, так и внешнего приложения.

Я думаю, что конфигурация Render правильная.

Итак, я покажу вам здесь часть своего кода, чтобы вы, надеюсь, могли обнаружить ошибку.

Структура моего проекта est la suivante:

/my-project
  /backend
    app.js
    events.json
    /data
      events.js
    /routes
      events.js
    /util
      error.js
      validation.js
  /frontend
    /build
      index.html
      // other build files
    src
      // my React source files
  • бэкэнд\app.js:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const eventRoutes = require('./routes/events');

const app = express();
const PORT = process.env.PORT || 8080;

app.use(bodyParser.json());
app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Methods', 'GET,POST,PATCH,DELETE');
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
  next();
});

// Serve static files from the React app
app.use(express.static(path.join(__dirname, '../frontend/build')));

// API routes
app.use('/events', eventRoutes);

// The "catchall" handler: for any request that doesn't match one above, send back React's index.html file.
app.get('*', (req, res) => {
  console.info('Serving index.html for request:', req.url);
  res.sendFile(path.join(__dirname, '../frontend/build', 'index.html'));
});

// Error handling middleware
app.use((error, req, res, next) => {
  const status = error.status || 500;
  const message = error.message || 'Something went wrong.';
  res.status(status).json({ message: message });
});

// Start the server
app.listen(PORT, () => {
  console.info(`Server is running on port ${PORT}`);
});
  • бэкэнд\данные\event.js:
const fs = require('node:fs/promises');
const path = require('path');
const { v4: generateId } = require('uuid');
const { NotFoundError } = require('../util/errors');

// Utilisation de path.resolve pour garantir le bon chemin d'accès
const dataFilePath = path.resolve(__dirname, '../events.json');

async function readData() {
  try {
    console.info('Reading data from:', dataFilePath); // Ajout de log pour vérifier le chemin
    const data = await fs.readFile(dataFilePath, 'utf8');
    return JSON.parse(data);
  } catch (error) {
    console.error('Failed to read data:', error);
    throw new Error('Could not read events data.');
  }
}

async function writeData(data) {
  try {
    console.info('Writing data to:', dataFilePath); // Ajout de log pour vérifier le chemin
    await fs.writeFile(dataFilePath, JSON.stringify(data));
  } catch (error) {
    console.error('Failed to write data:', error);
    throw new Error('Could not write events data.');
  }
}

async function getAll() {
  const storedData = await readData();
  if (!storedData.events) {
    throw new NotFoundError('Could not find any events.');
  }
  return storedData.events;
}

async function get(id) {
  const storedData = await readData();
  if (!storedData.events || storedData.events.length === 0) {
    throw new NotFoundError('Could not find any events.');
  }

  const event = storedData.events.find(ev => ev.id === id);
  if (!event) {
    throw new NotFoundError('Could not find event for id ' + id);
  }

  return event;
}

async function add(data) {
  const storedData = await readData();
  storedData.events.unshift({ ...data, id: generateId() });
  await writeData(storedData);
}

async function replace(id, data) {
  const storedData = await readData();
  if (!storedData.events || storedData.events.length === 0) {
    throw new NotFoundError('Could not find any events.');
  }

  const index = storedData.events.findIndex(ev => ev.id === id);
  if (index < 0) {
    throw new NotFoundError('Could not find event for id ' + id);
  }

  storedData.events[index] = { ...data, id };

  await writeData(storedData);
}

async function remove(id) {
  const storedData = await readData();
  const updatedData = storedData.events.filter(ev => ev.id !== id);
  await writeData({ events: updatedData });
}

exports.getAll = getAll;
exports.get = get;
exports.add = add;
exports.replace = replace;
exports.remove = remove;

Я могу дать вам более подробную информацию, если это необходимо.

У меня это сработало нормально, вы пытались получить доступ к URL-адресу напрямую? можете ли вы предоставить код реакции? может быть, ваша ссылка на репозиторий git?

Lã Ngọc Hải 24.05.2024 05:59

Что вы имеете в виду, что у вас это работало нормально? Что вы видите, когда вы нажимаете на навигационную ссылку «Мероприятия» и затем обновляете страницу? Да, я попытался получить доступ к этому URL-адресу response-router-events-j6yu.onrender.com/events напрямую и получил те же данные JSON. Вот мой код React по ссылке на репозиторий GitHub: github.com/sofiane-abou-abderrahim/react-router-events/tree/‌​…. Пожалуйста, используйте ветку «тест».

Sofiane Abou Abderrahim 24.05.2024 12:58
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
53
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это определенно проблема приложения, а не неправильная конфигурация Render.

Действительно, здесь происходит путаница в маршрутизации на стороне клиента и путях на сервере.

Когда вы просматриваете сайт и нажимаете на навигационную ссылку «События», это на самом деле не загружается /events с сервера — это изменение адреса React Router, чтобы он выглядел так, как будто это тот путь, а затем ваш JS загружается /events с сервера. .

При обновлении вы указываете браузеру загрузиться с /events — это путь, по которому загружается JSON.

Чтобы решить эту проблему, вам следует обновить путь к серверу /events (https://github.com/sofiane-abou-abderrahim/react-router-events/blob/test/backend/app.js#L21 ), чтобы он выглядел примерно так: /data, а затем обновите свой JS, чтобы получить данные из /data. ( https://github.com/sofiane-abou-abderrahim/react-router-events/blob/test/frontend/src/pages/Events.js#L21)

Таким образом, нажатие на «События» изменит браузер на /events и загрузит данные из /data, обновление означает, что ваш «* catch all path in server» будет перенаправлен, и React Router обработает его.

Другие вопросы по теме