URL-адреса React-маршрутизатора не работают при обновлении или записи вручную

Я использую React-роутер, и он отлично работает, пока я нажимаю на кнопки ссылок, но когда я обновляю свою веб-страницу, она не загружает то, что я хочу.

Например, я нахожусь в localhost/joblist и все в порядке, потому что я приехал сюда, нажимая на ссылку. Но если я обновлю веб-страницу, я получу:

Cannot GET /joblist

По умолчанию это не сработало. Первоначально у меня был URL как localhost/#/ и localhost/#/joblist и они работали отлично. Но мне не нравится этот вид URL, поэтому, пытаясь стереть этот #, я написал:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

Эта проблема не возникает с localhost/, эта всегда возвращает то, что я хочу.

РЕДАКТИРОВАТЬ: Это приложение одностраничное, поэтому /joblist не нужно ничего спрашивать на каком-либо сервере.

EDIT2: весь мой маршрутизатор.

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

Ответ 1

Глядя на комментарии к принятому ответу и общий характер этого вопроса ("не работает"), я подумал, что это может быть хорошим местом для некоторых общих объяснений по вопросам, связанным с этим.Таким образом, этот ответ предназначен в качестве справочной информации/разработки по конкретному варианту использования ОП.Пожалуйста, потерпите меня.

Сторона server- против стороны клиента

Первая важная вещь, которую нужно понять, это то, что теперь есть 2 места, где URL интерпретируется, тогда как раньше было "1" в "старые времена". В прошлом, когда жизнь была проста, какой-то пользователь отправлял запрос на http://example.com/about на сервер, который проверял часть пути URL-адреса, определял, что пользователь запрашивает страницу about, а затем отправлял обратно стр.

С маршрутизацией на стороне клиента, которую предоставляет React-Router, все не так просто. Во-первых, у клиента еще нет загруженного кода JS. Так что самый первый запрос всегда будет на сервер. Затем будет возвращена страница, которая содержит необходимые теги сценариев для загрузки React, React Router и т.д. Только после загрузки этих сценариев начинается фаза 2. На этапе 2, когда пользователь нажимает, например, на навигационную ссылку "О нас", URL-адрес изменяется локально только на http://example.com/about (это стало возможным благодаря History API), но не запрашивает сервер сделано. Вместо этого React Router делает свое дело на стороне клиента, определяет, какое представление React отображать, и отображает его. Предполагая, что вашей странице about не нужно совершать какие-либо вызовы REST, это уже сделано. Вы перешли из дома в О нас без каких-либо запросов к серверу.

Таким образом, в основном, когда вы нажимаете на ссылку, запускается Javascript, который обрабатывает URL в адресной строке, не вызывая обновления страницы, что, в свою очередь, заставляет React Router выполнять переход страницы на стороне клиента.

Но теперь подумайте, что произойдет, если скопировать и вставить URL-адрес в адресную строку и отправить его другу по электронной почте. Ваш друг еще не загрузил ваш сайт. Другими словами, она все еще в фазе 1. На ее компьютере еще не запущен React Router. Поэтому ее браузер отправит запрос на сервер по http://example.com/about.

И вот тут начинается твоя проблема. До сих пор вы могли бы просто разместить статический HTML в корне вашего сервера. Но это даст 404 ошибки для всех других URL-адресов при запросе с сервера. Те же URL-адреса прекрасно работают на стороне клиента, потому что там React Router выполняет маршрутизацию за вас, но они терпят неудачу на стороне сервера, если вы не заставите свой сервер их понять.

Объединение server- и маршрутизации на стороне клиента

Если вы хотите, чтобы URL-адрес http://example.com/about работал как на server-, так и на стороне клиента, вам необходимо настроить для него маршруты как на server-, так и на стороне клиента. Имеет смысл правильно?

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

,

Обход проблемы в целом: Hash History

Если вместо истории браузеров использовать историю хэшей, ваш URL для страницы about будет выглядеть примерно так: http://example.com/#/about Часть после символа хеш (#) не отправляется на сервер. Таким образом, сервер видит только http://example.com/ и отправляет страницу индекса, как и ожидалось. React-Router подберет деталь #/about и покажет правильную страницу.

Недостатки:

  • "уродливые" URL
  • Рендеринг стороны server- невозможен при таком подходе. Что касается поисковой оптимизации (SEO), ваш сайт состоит из одной страницы, на которой почти нет контента.

,

Вместилище разнообразных предметов

При таком подходе вы используете историю браузеров, но просто настраиваете ловушку на сервере, который отправляет /* в index.html, эффективно предоставляя вам ту же ситуацию, что и в истории хэшей. Тем не менее, у вас есть чистые URL-адреса, и вы можете улучшить эту схему позже, не делая недействительными все ваши избранные пользователи.

Недостатки:

  • Более сложная настройка
  • Все еще нет хорошего SEO

,

Гибридный

В гибридном подходе вы расширяете общий сценарий, добавляя конкретные сценарии для определенных маршрутов. Вы можете сделать несколько простых PHP-скриптов, чтобы вернуть наиболее важные страницы вашего сайта с включенным контентом, чтобы робот Googlebot мог хотя бы посмотреть, что на вашей странице.

Недостатки:

  • Еще сложнее настроить
  • Только хороший SEO для тех маршрутов, которые вы предоставляете специальную обработку
  • Дублирование кода для рендеринга контента на сервере и клиенте

,

изоморфный

Что если мы используем Node JS в качестве нашего сервера, чтобы мы могли запускать один и тот же код JS на обоих концах? Теперь у нас есть все наши маршруты, определенные в одной конфигурации реакции-маршрутизатора, и нам не нужно дублировать наш код рендеринга. Это, так сказать, "Святой Грааль". Сервер отправляет ту же самую разметку, которую мы получили бы в случае перехода страницы на клиенте. Это решение является оптимальным с точки зрения SEO.

Недостатки:

  • Сервер должен (быть в состоянии) запустить JS. Я экспериментировал с Java icw Nashorn, но он не работает для меня. На практике это в основном означает, что вы должны использовать сервер на базе Node JS.
  • Многие сложные экологические проблемы (использование window на стороне server- и т.д.)
  • Крутая кривая обучения

,

Какой я должен использовать?

Выберите тот, который вы можете сойти с рук. Лично я думаю, что все достаточно просто настроить, так что это мой минимум. Эта настройка позволяет вам улучшать вещи с течением времени. Если вы уже используете Node JS в качестве серверной платформы, я бы определенно занялся созданием изоморфного приложения. Да, сначала это сложно, но как только вы освоитесь, это действительно очень элегантное решение проблемы.

В общем, для меня это было бы решающим фактором. Если мой сервер работает на Node JS, я бы стал изоморфным; В противном случае я бы выбрал решение Catch-all и просто расширил его (Гибридное решение), когда время идет, а требования SEO требуют этого.

Если вы хотите больше узнать об изоморфном (также называемом "универсальным") рендеринге с помощью React, есть несколько хороших учебников по этому вопросу:

Кроме того, чтобы начать, я рекомендую взглянуть на некоторые стартовые наборы. Выберите тот, который соответствует вашему выбору для технологического стека (помните, React - это просто V в MVC, вам нужно больше вещей для создания полноценного приложения). Начните с просмотра того, что опубликовано самим Facebook:

Или выберите один из множества сообществ. Теперь есть хороший сайт, который пытается проиндексировать их все:

Я начал с этого:

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

Удачи в вашем квесте!

Ответ 2

Все ответы здесь очень полезны, для меня работало то, что я настроил мой сервер Webpack для ожидания маршрутов.

devServer: {
   historyApiFallback: true,
   contentBase: './',
   hot: true
},

historyApiFallback - это то, что исправило эту проблему для меня. Теперь маршрутизация работает правильно, и я могу обновить страницу или ввести URL-адрес напрямую. Не нужно беспокоиться об обходах на вашем сервере узлов. Этот ответ, очевидно, работает, только если вы используете веб-пакет.

ОБНОВЛЕНИЕ: см. мой ответ здесь для более подробной причины, почему это необходимо:fooobar.com/questions/31538/...

Ответ 3

Вы можете изменить свой htaccess и вставить это:

RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

Я использую react: "^15.3.2", react-router: "^3.0.0", history: "^4.3.0",

Ответ 4

Для пользователей React Router V4 :

Если вы попытаетесь решить эту проблему с помощью метода истории хеша, упомянутого в других ответах, обратите внимание, что

<Router history={hashHistory} >

не работает в V4, используйте вместо этого HashRouter:

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

Ссылка: HashRouter

Ответ 5

Маршрутизатор можно вызывать двумя разными способами, в зависимости от того, происходит ли навигация на клиенте или на сервере. Он настроен для работы на стороне клиента. Ключевым параметром является второй метод , расположение.

Когда вы используете компонент React Router Link, он блокирует навигацию браузера и вызывает переход для выполнения клиентской навигации. Вы используете HistoryLocation, поэтому он использует API истории HTML5 для завершения иллюзии навигации, моделируя новый URL-адрес в адресной строке. Если вы используете старые браузеры, это не сработает. Вам нужно будет использовать компонент HashLocation.

Когда вы нажмете обновление, вы обойдете весь код React и React Router. Сервер получает запрос для /joblist, и он должен что-то вернуть. На сервере вам необходимо передать путь, который был запрошен методу run, чтобы он отображал правильный вид. Вы можете использовать ту же карту маршрутов, но вам, вероятно, потребуется другой вызов Router.run. Как указывает Чарльз, вы можете использовать переписывание URL, чтобы справиться с этим. Другой вариант - использовать сервер node.js для обработки всех запросов и передать значение пути в качестве аргумента местоположения.

В экспресс, например, он может выглядеть следующим образом:

var app = express();

app.get('*', function (req, res) { // This wildcard method handles all requests

    Router.run(routes, req.path, function (Handler, state) {
        var element = React.createElement(Handler);
        var html = React.renderToString(element);
        res.render('main', { content: html });
    });
});

Обратите внимание, что путь запроса передается на run. Для этого вам понадобится серверный механизм просмотра, с помощью которого вы можете передать отображаемый HTML. Существует ряд других соображений, использующих renderToString и при запуске React на сервере. После того, как страница будет отображаться на сервере, когда ваше приложение загрузится на клиенте, оно снова отобразится, при необходимости обновив HTML-версию на стороне сервера.

Ответ 6

В head.html head добавьте следующее:

<base href="/">
<!-- This must come before the css and javascripts -->

Затем при работе с сервером webpack dev используйте эту команду.

webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback

--history-api-fallback - важная часть

Ответ 7

Я использовал create-реагировать на приложение, чтобы сделать веб-сайт только что и тот же вопрос, представленный здесь. Я использую BrowserRouting из BrowserRouting react-router-dom. Я работаю на сервере Nginx, и я решил добавить следующее в /etc/nginx/yourconfig.conf

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

Что соответствует добавлению следующего к .htaccess в случае, если вы используете Appache

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

Это также, кажется, решение, предложенное самими Facebook и может быть найдено здесь

Ответ 9

Если вы принимаете приложение-ответ через AWS Static S3 Hosting & CloudFront

Эта проблема представила CloudFront, ответив сообщением об отказе в доступе 403, потому что он ожидал /some/other/path для существования в моей папке S3, но этот путь существует только внутри React routing с реактивным маршрутизатором.

Решение состояло в том, чтобы настроить правило Error Pages. Перейдите в настройки CloudFront и выберите свой дистрибутив. Затем перейдите на вкладку "Страницы ошибок". Нажмите "Создать пользовательский ответ об ошибке" и добавьте запись для 403, так как это код состояния ошибки, который мы получаем. Задайте путь страницы ответа в /index.html и код состояния до 200. Конечный результат удивляет меня своей простотой. Страница индексирования обслуживается, но URL-адрес сохраняется в браузере, поэтому, как только приложение реагирует на загрузку, он обнаруживает путь URL-адреса и переходит на нужный маршрут.

Ошибка страницы 403 Правило

Ответ 10

Это может решить вашу проблему

Я также столкнулся с той же проблемой в приложении ReactJS в режиме производства. Вот 2 решение проблемы.

1. Измените историю маршрутизации на "hashHistory" вместо browserHistory вместо

<Router history={hashHistory} >
   <Route path="/home" component={Home} />
   <Route path="/aboutus" component={AboutUs} />
</Router>

Теперь создайте приложение с помощью команды

sudo npm run build

Затем поместите папку сборки в папку var/www/. Теперь приложение работает нормально с добавлением тега # в каждом URL-адресе. как

локальный/#/дома  локальный /#/ABOUTUS

Решение 2. Без тега # с помощью browserHistory,

Установите вашу историю = {browserHistory} в своем маршрутизаторе, теперь создайте ее с помощью sudo npm run build.

Вам нужно создать файл "conf", чтобы решить страницу 404 не найдена, файл conf должен быть таким.

откройте свой терминал, введите приведенные ниже команды

cd/etc/apache2/sites-available Ls nano sample.conf Добавьте в него содержимое ниже.

<VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName 0.0.0.0
    ServerAlias 0.0.0.0
    DocumentRoot /var/www/html/

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
    <Directory "/var/www/html/">
            Options Indexes FollowSymLinks
            AllowOverride all
            Require all granted
    </Directory>
</VirtualHost>

Теперь вам нужно включить файл sample.conf с помощью следующей команды

cd /etc/apache2/sites-available
sudo a2ensite sample.conf

тогда он попросит вас перезагрузить сервер apache, используя    Перезагрузка или перезапуск службы sudo apache2

затем откройте папку localhost/build и добавьте файл .htaccess с содержанием ниже.

   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_FILENAME} !-l
   RewriteRule ^.*$ / [L,QSA]

Теперь приложение работает нормально.

Примечание. Измените IP-адрес 0.0.0.0 на свой локальный IP-адрес.

Если у вас есть какие-либо сомнения по этому поводу, не стесняйтесь поднять комментарий.

Я надеюсь, что это полезно для других.

Ответ 11

Производственный стек: React, React Router v4, BrowswerRouter, Express, Nginx

1) User BrowserRouter для симпатичных URL-адресов

// app.js

import { BrowserRouter as Router } from 'react-router-dom'

const App = () {
  render() {
    return (
        <Router>
           // your routes here
        </Router>
    )
  }
}

2) Добавьте index.html ко всем неизвестным запросам с помощью /*

// server.js

app.get('/*', function(req, res) {   
  res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
    if (err) {
      res.status(500).send(err)
    }
  })
})

3) пакетный webpack -p пакет с webpack -p

4) запустите nodemon server.js или node server.js

EDIT: вы можете позволить nginx обрабатывать это в блоке сервера и игнорировать шаг 2:

location / {
    try_files $uri /index.html;
}

Ответ 12

Добавьте это к webpack.congif.js

devServer: {
    historyApiFallback: true
}

Ответ 13

Если вы используете приложение Create React:

Тем не менее, эта проблема с решениями для многих основных хостинг-платформ хорошо описана ЗДЕСЬ на странице Создать приложение React. Например, я использую React Router v4 и Netlify для своего кода веб-интерфейса. Все, что нужно, это добавить 1 файл в мою общую папку ("_redirects") и одну строку кода в этом файле:

/*  /index.html  200

Теперь мой веб-сайт правильно отображает пути, такие как mysite.com/pricing, при входе в браузер или при обновлении.

Ответ 14

Попробуйте добавить файл ".htaccess" в общую папку с приведенным ниже кодом.

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]  

Ответ 15

Я нашел решение для моего SPA с реагирующим маршрутизатором (Apache). Просто добавьте в .htaccess

<IfModule mod_rewrite.c>

  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]

</IfModule>

источник: https://gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042

Ответ 16

Если у вас есть резерв на ваш index.html, убедитесь, что в вашем файле index.html есть следующее:

<script>
  System.config({ baseURL: '/' });
</script>

Это может отличаться от проекта к проекту.

Ответ 17

Эта тема немного устарела и решена, но я хотел бы предложить вам простое, ясное и лучшее решение. Он работает, если вы используете веб-сервер.

Каждый веб-сервер имеет возможность перенаправлять пользователя на страницу с ошибкой в ​​случае http 404. Для решения этой проблемы вам необходимо перенаправить пользователя на страницу индекса.

Если вы используете базовый сервер Java (tomcat или любой сервер приложений Java), решение может быть следующим:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- WELCOME FILE LIST -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- ERROR PAGES DEFINITION -->
    <error-page>
        <error-code>404</error-code>
        <location>/index.jsp</location>
    </error-page>

</web-app>

Пример:

  • GET http://example.com/about
  • Веб-сервер выбрасывает http 404, потому что эта страница не существует на стороне сервера.
  • Конфигурация страницы ошибки сообщает серверу, который отправляет страницу index.jsp обратно пользователю
  • тогда JS выполнит оставшуюся часть задания со стороны clien, потому что URL-адрес на стороне клиента по-прежнему http://example.com/about.

То есть, больше не нужно магии:)

Ответ 18

Если вы размещаете свое приложение-ответ в IIS, просто добавьте файл web.config, содержащий:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" path="/" responseMode="ExecuteURL" />
    </httpErrors>
  </system.webServer>
</configuration>

Это означает, что сервер IIS вернет основную страницу клиенту вместо ошибки 404 и не будет необходимости использовать историю хэша.

Ответ 19

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

Мой главный jsx содержит следующее:

<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />

Это отлично подходит для первой сопоставленной ссылки, но когда идентификатор: id изменяется в выражениях <Link>, вложенных в эту страницу подробностей модели, url изменяется в строке браузера, но содержимое страницы не изначально менялось, чтобы отразить связанный модель.

Проблема заключалась в том, что я использовал props.params.id для установки модели в componentDidMount. Компонент просто монтируется один раз, так что это означает, что первая модель является той, которая хранится на странице, а последующие ссылки меняют реквизиты, но оставляют страницу неизменной.

Установка модели в состоянии компонента как в componentDidMount, так и в componentWillReceiveProps (где она основана на следующих реквизитах) решает проблему, а содержимое страницы изменяется, чтобы отобразить желаемую модель.

Ответ 20

Если вы используете Express или какой-либо другой фреймворк в бэкэнде, вы можете добавить аналогичную конфигурацию, как показано ниже, и проверить открытый путь Webpack в конфигурации, он должен работать нормально даже при перезагрузке, если вы используете BrowserRouter

expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
});

Ответ 21

Если вы используете firebase, все, что вам нужно сделать, это убедиться, что у вас есть свойство rewrites в вашем файле firebase.json в корне вашего приложения (в разделе хостинга).

Например:

{ 
  "hosting": {
    "rewrites": [{
      "source":"**",
      "destination": "/index.html"
    }]    
  }
}

Надеюсь, это избавит кого-то еще от разочарования и впустую.

Счастливое кодирование...

Дальнейшее чтение по теме:

https://firebase.google.com/docs/hosting/full-config#rewrites

Firebase CLI: "Настроить как одностраничное приложение (переписать все URL-адреса в /index.html)"

Ответ 22

Если вы хостинг в IIS; Добавление этого в мой webconfig решило мою проблему

<httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
    <remove statusCode="500" subStatusCode="100" />
    <remove statusCode="500" subStatusCode="-1" />
    <remove statusCode="404" subStatusCode="-1" />
    <error statusCode="404" path="/" responseMode="ExecuteURL" />
    <error statusCode="500" prefixLanguageFilePath="" path="/error_500.asp" responseMode="ExecuteURL" />
    <error statusCode="500" subStatusCode="100" path="/error_500.asp" responseMode="ExecuteURL" />
</httpErrors>

Вы можете сделать аналогичную конфигурацию для любого другого сервера

Ответ 23

В случае, если кто-то ищет решение для React JS SPA с Laravel. Принятый ответ - лучшее объяснение того, почему такие проблемы происходят. Как уже объяснялось, вам необходимо настроить как клиентскую, так и серверную сторону. В свой шаблон клипа включите файл js в комплекте, обязательно используйте URL facade, как этот

<script src="{{ URL::to('js/user/spa.js') }}"></script>

В ваших маршрутах обязательно добавьте это в основную конечную точку, где находится шаблон клинка. Например,

Route::get('/setting-alerts', function () {
   return view('user.set-alerts');
});

Вышеприведенное является основной конечной точкой для шаблона клинка. Теперь добавьте необязательный маршрут,

Route::get('/setting-alerts/{spa?}', function () {
  return view('user.set-alerts');
});

Проблема заключается в том, что сначала загружается шаблон клинка, а затем реагирует маршрутизатор. Итак, когда вы загружаете '/setting-alerts', он загружает html и js. Но когда вы загружаете '/setting-alerts/about', он сначала загружается со стороны сервера. Поскольку на стороне сервера в этом месте ничего нет, он не возвращается. Когда у вас есть этот дополнительный маршрутизатор, он загружает ту же страницу и также загружает маршрутизатор, а затем реагирует загрузчик, решает, какой компонент будет отображаться. Надеюсь, это поможет.

Ответ 24

Исправление ошибки "невозможно получить /URL" при обновлении или при непосредственном вызове URL.

Сконфигурируйте свой webpack.config.js так, чтобы по указанной ссылке ожидались маршруты, подобные этой.

module.exports = {
  entry: './app/index.js',
  output: {
       path: path.join(__dirname, '/bundle'),
       filename: 'index_bundle.js',
       publicPath: '/'
  },

Ответ 25

Поскольку я использую .Net Core MVC, мне помогло нечто подобное:

    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var url = Request.Path + Request.QueryString;
            return App(url);
        }

        [Route("App")]
        public IActionResult App(string url)
        {
            return View("/wwwroot/app/build/index.html");
        }
   }

В основном на стороне MVC все несоответствующие маршруты попадут в Home/Index как указано в файле startup.cs. Внутри Index можно получить исходный URL-адрес запроса и передать его, где это необходимо.

startup.cs

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });

Ответ 26

У меня была такая же проблема, и это решение работало для нас..

Фон:

Мы размещаем несколько приложений на одном сервере. Когда мы обновим сервер, вы не поймете, где искать наш индекс в папке dist для этого конкретного приложения. Вышеупомянутая ссылка приведет вас к тому, что сработало для нас... Надеюсь, это поможет, поскольку мы потратили немало времени на разработку решения для наших нужд.

Мы используем:

package.json

"dependencies": {
"babel-polyfill": "^6.23.0",
"ejs": "^2.5.6",
"express": "^4.15.2",
"prop-types": "^15.5.6",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-persist": "^4.6.0",
"redux-thunk": "^2.2.0",
"webpack": "^2.4.1"
}

my webpack.config.js

webpack.config.js

/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const babelPolyfill = require('babel-polyfill');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/views/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    'babel-polyfill', './app/index.js'
  ],
  output: {
    path: __dirname + '/dist/your_app_name_here',
    filename: 'index_bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      query : {
          presets : ["env", "react", "stage-1"]
      },
      exclude: /node_modules/
    }]
  },
  plugins: [HTMLWebpackPluginConfig]
}

my index.js

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import Routes from './Routes'
import { Provider } from 'react-redux'
import { createHistory } from 'history'
import { useRouterHistory } from 'react-router'
import configureStore from './store/configureStore'
import { syncHistoryWithStore } from 'react-router-redux'
import { persistStore } from 'redux-persist'

const store = configureStore();

const browserHistory = useRouterHistory(createHistory) ({
  basename: '/your_app_name_here'
})
const history = syncHistoryWithStore(browserHistory, store)

persistStore(store, {blacklist: ['routing']}, () => {
  console.log('rehydration complete')
})
// persistStore(store).purge()


ReactDOM.render(
    <Provider store={store}>
      <div>
        <Routes history={history} />
      </div>
    </Provider>,
  document.getElementById('mount')
)

my app.js

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/dist'));
// app.use(express.static(__dirname + '/app/assets'));
app.set('views', __dirname + '/dist/your_app_name_here');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

app.get('/*', function (req, res) {
    res.render('index');
});

app.listen(8081, function () {
  console.log('MD listening on port 8081!');
});

Ответ 27

Решение для Preact с preact-роутером

Работает с обновлением и прямым доступом

Для тех, кто узнает об этом через Google, вот демо-версия preact-router + история хешей:

const { h, Component, render } = preact; /** @jsx h */
const { Router } = preactRouter;
const { createHashHistory } = History;
const App = () => (
    <div>
        <AddressBar />

        <Router history={createHashHistory()}>
            <div path="/">
                <p>
                    all paths in preact-router are still /normal/urls.
                    using hash history rewrites them to /#/hash/urls
                </p>
                Example: <a href="/page2">page 2</a>
            </div>
            <div path="/page2">
                <p>Page Two</p>
                <a href="/">back to home</a><br/>
            </div>
        </Router>
    </div>
);

jsfiddle

Ответ 29

Для тех, кто использует IIS 10, это то, что вы должны сделать, чтобы сделать это правильно. Убедитесь, что вы используете browserHistory с этим. Что касается ссылки, я дам код для маршрутизации, но это не имеет значения, что важно для следующего шага после кода компонента ниже:

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />    
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

Поскольку проблема заключается в том, что IIS получает запрос от клиентских браузеров, он будет интерпретировать URL-адрес так, как будто он запрашивает страницу, а затем возвращает страницу 404, так как нет доступной страницы. Выполните следующие действия:

  1. Открыть IIS
  2. Разверните сервер, затем откройте папку "Сайты"
  3. Нажмите веб-сайт/приложение
  4. Перейдите на страницу ошибок
  5. Откройте элемент статуса ошибки 404 в списке
  6. Вместо опции "Вставить содержимое из статического файла в ответ на ошибку" измените его на "Выполнить URL-адрес на этом сайте" и добавьте "/" значение косой черты в URL-адрес.

И теперь он будет работать нормально.

enter image description here enter image description here

Я надеюсь, что это помогает. :-)