Не удалось маршрутизировать при развертывании приложения React + Express.js на сервере IIS

У меня есть приложение React, созданное Create-React-app и Redux вместе с бэкэндом Node.js (в частности, Express.js). В файле внешнего интерфейса package.json я установил «прокси: http://localhost:5000», чтобы перенаправить все вызовы API из приложения реагирования на внутренний сервер. Тем временем внутренний сервер одновременно работает и прослушивает порт localhost: 5000.

Структура приложения показана ниже: Структура приложения

Внешний интерфейс

Файл package.json в папке клиента (интерфейс) настраивает прокси следующим образом.

{
  ...,
  "proxy": "http://localhost:5000"
}

В App.js (точка входа во внешний интерфейс) я создал несколько URL-маршрутов с помощью реакции-маршрутизатора-dom:

 return (
    <ThemeProvider theme = {theme}>
      <Provider store = {store}>
        <Fragment>
          <Router>
            <div
              className='App'
              style = {{ fontFamily: 'Montserrat', fontWeight: '500' }}>
              <header>
                <Navbar />{' '}
              </header>

              <div>
                <Routes>
                  <Route exact path='/' element = {<Home />} />
                  <Route exact path='/home' element = {<Home />} />
                  <Route exact path='/dashboard' element = {<Dashboard />} />
                  <Route exact path='/about' element = {<About />} />
                  <Route exact path='/register' element = {<Register />} />
                  <Route exact path='/login' element = {<Login />} />
                  <Route exact path='/forgot' element = {<ForgotPassword />} />
                  <Route path='/reset' element = {<ResetPassword />} />
                  <Route path='/avatar' element = {<ChangeAvatar />} />
                  <Route
                    exact
                    path='/systemtables'
                    element = {<SystemTables />}
                  />
                  <Route exact path='/profiles' element = {<ProfileMain />} />
                  <Route exact path='/companies' element = {<CompanyMain />} />

                  ...
                  
                </Routes>
              </div>

            </div>
          </Router>
        </Fragment>
      </Provider>
    </ThemeProvider>
);

Бэкэнд

Файл package.json в корне приложения (папка AAQCS) выглядит следующим образом:

{
  ...,
  "scripts": {
    "start": "node index.js",
    "server": "nodemon index.js --ignore temp/",
    "client": "npm start --prefix client",
    "clientinstall": "npm install -prefix client",
    "dev": "concurrently \"npm run server\" \"npm run client\""
  },
  "devDependencies": {
    "concurrently": "^6.0.2",
    "nodemon": "^2.0.19"
  }
}

В «web-server.js» (точка входа в серверную часть) у меня есть код ниже:

    const app = express();
    app.use(cors());
    httpServer = http.createServer(app);
    //Set server side static uploads folder receiving front-end upload request.
    app.use('/public', express.static('public'));

    // Combines logging info from request and response
    app.use(morgan('combined'));

    //Init Middleware to receive request body
    app.use(express.json({ extended: false, limit: '50000mb' }));
    app.use(favicon(__dirname + '/images/favicon.ico'));

    //Serve any static files built by React
    app.use(express.static(path.join(__dirname, 'client/build')));

    app.get('/', function (req, res) {
      res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
    });

    //Define Routes
    app.use('/api/users', require('./routes/users'));
    app.use('/api/auth', require('./routes/auth'));
    app.use('/api/asset', require('./routes/asset'));
    app.use('/api/companies', require('./routes/companies'));
    ...

    httpServer
      .listen(webServerConfig.port)
      .on('listening', () => {
        console.info(
         `Web server listening on localhost:${webServerConfig.port}`
        );

        resolve();
      })
      .on('error', (err) => {
        reject(err);
      });

Внутренний сервер прослушивает локальный хост: 5000.

В настоящее время у меня есть эти правила в файле web.config:

            <rules>
                <clear />
                <rule name = "RedirectToBackend" stopProcessing = "true">
                    <match url = "^api/(.*)" />
                    <conditions logicalGrouping = "MatchAll" trackAllCaptures = "false" />
                    <action type = "Redirect" url = "http://localhost:5000/api/{R:1}" />
                </rule>
                <rule name = "React Routes" stopProcessing = "true">
                    <match url = ".*" />
                    <conditions logicalGrouping = "MatchAll" trackAllCaptures = "true">
                        <add input = "{REQUEST_FILENAME}" matchType = "IsFile" negate = "true" />
                        <add input = "{REQUEST_FILENAME}" matchType = "IsDirectory" negate = "true" />
                        <add input = "{REQUEST_URI}" pattern = "^api/(.*)" negate = "true" />
                    </conditions>
                    <action type = "Redirect" url = "{R:0}" />
                </rule>
            </rules>

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

После того, как я поместил сборку в IIS, я могу запустить страницу входа, но когда я нажимаю кнопку «Вход», я получаю ошибку: «POST http://localhost:3000/api/auth 500 (ошибка модуля перезаписи URL-адреса.)»

Мои вопросы:

  1. Что-то не так в моих правилах маршрутизации в файле web.config?
  2. По сути, я хочу добиться того, чтобы все вызовы API в формате «/api/xxxx» были перенаправлены на localhost:5000, где прослушивает внутренний сервер. Все остальные запросы без формата «/api/xxxx» должны следовать маршрутам, установленным в приложении реагирования. Как я могу создать правила для достижения этой цели.
<action type = "Redirect" url = "http://localhost:5000/api/{R:1}" /> недействителен. Вы не можете просто перенаправить туда браузеры (этот URL-адрес недействителен на компьютерах со стороны браузера), и вам необходимо настроить полный обратный прокси-сервер.
Lex Li 14.09.2023 02:35

Поэтому я изменил тип на Rewrite и установил ARR, как предложил @Yurong Dai. Теперь я успешно вошел в систему, но не все маршруты реагирования работают, хотя я настроил маршруты точно так же в App.js.

Ning Zheng 14.09.2023 18:15
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
55
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вам необходимо установить ARR и включить функцию прокси-сервера для работы с IIS в качестве обратного прокси-сервера, который может перенаправлять все вызовы API в формате «/api/xxxx» на внутренний сервер NodeJS.

Убедитесь, что для типа действия перезаписи URL-адреса установлено значение «Перезапись», а не «Перенаправление», поскольку вы хотите передать запрос через прокси, а не выполнять перенаправление.

<rule name = "RedirectToBackend" stopProcessing = "true">
    <match url = "^api/(.*)" />
    <action type = "Rewrite" url = "http://localhost:5000/api/{R:1}" />
</rule>

Кроме того, все остальные запросы без формата «/api/xxxx» должны следовать маршруту, установленному в приложении React. Вам необходимо создать следующее правило, которое будет перезаписывать все запросы, не относящиеся к API, на корневой URL-адрес («/»), где их будет обрабатывать маршрутизация приложения React.

<rule name = "React Routes" stopProcessing = "true">
    <match url = ".*" />
    <conditions logicalGrouping = "MatchAll" trackAllCaptures = "true">
        <add input = "{REQUEST_FILENAME}" matchType = "IsFile" negate = "true" />
        <add input = "{REQUEST_FILENAME}" matchType = "IsDirectory" negate = "true" />
        <add input = "{REQUEST_URI}" pattern = "^/api/(.*)" negate = "true" />
    </conditions>
    <action type = "Rewrite" url = "/" />
</rule>

Спасибо за подробное решение. Я вошел в систему правильно. Я также правильно обработал большую часть вызовов, не связанных с API, с помощью ваших правил, приведенных выше, за исключением некоторых маршрутизаций, когда я нажимал кнопку, например: сервер выдал мне сообщение Cannot GET /assessmentaudits. У меня была точно такая же настройка маршрутизации в App.js, как и в других, таких как /login, /register и т. д. Нужно ли мне специально прописывать этот URL в правилах?

Ning Zheng 14.09.2023 17:57

Однако с вышеуказанной ошибкой есть еще кое-что: когда я навожу курсор на кнопку, запускающую компонент assessmentaudits, в левом нижнем углу экрана отображается ссылка http://localhost:3000/assessmentaudits. Но когда я нажал кнопку, URL-адрес в браузере фактически превратился в http://localhost:5000/assessmentaudits, что и вызвало вышеуказанную ошибку. Что я сделал не так? Ценю вашу помощь.

Ning Zheng 14.09.2023 20:48

Настроили ли вы маршрут /assesmentaudits, соответствующий компоненту Assessmentaudits в App.js? Создали ли вы какие-либо другие правила помимо правил перезаписи в ответе выше?

YurongDai 15.09.2023 05:12

Я предлагаю вам попробовать использовать FRT для отслеживания запроса, вы увидите, как правила используются внутри. Learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/‌​…

YurongDai 15.09.2023 05:34

Спасибо за ваш быстрый ответ. Да, у меня был этот код в App.js: <Route exact path='/assessmentaudits' element = {<AssessmentAudits />} />. Я вспомнил, что когда я проверял «Включить прокси в ARR», я также проверял «Использовать перезапись URL-адреса» для проверки входящих запросов в разделе «Тип прокси» и ставил localhost:5000 в поле «Обратный прокси». Увидев ваш ответ, я снял флажок «Использовать перезапись URL-адреса», чтобы проверить входящие запросы и применить изменения. Оставит ли это «другое правило» в системе? Завтра я обязательно рассмотрю ваше предложение по отслеживанию FRT и сообщу вам результат.

Ning Zheng 15.09.2023 06:28

Решена проблема, когда я изменил URL-адрес «/assessmentaudits» на «/asmtaudits» в маршрутизациях React в App.js. Не знаю, почему это произошло. Возможно, этот URL-адрес случайно совпадал с первым уровнем нашего домена, который называется «assessmentaudit.ma....» (как такое могло случиться, даже если доменное имя не заканчивается на «s»). Огромное спасибо за помощь, ЮронгДай. Ты мужчина!!!

Ning Zheng 15.09.2023 20:13

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