Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: DavidDevОтветов: 12

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

Например, я нахожусь в 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);
});
  • если вы не используете htaccess для загрузки своей основной туристической страницы и не укажете маршрутизатору использовать location.pathname, это не сработает. CJT3 20.01.2015
  • Как вы стерли этот символ #? Спасибо! SudoPlz 06.06.2015
  • Если вы размещаете свое приложение для реагирования в корзине S3, вы можете просто установить для документа с ошибкой значение index.html. Это обеспечит попадание в index.html несмотря ни на что. Trevor Hutto 30.07.2016
  • В моем случае он отлично работает в Windows, но не в Linux. Ejaz Karim 04.12.2017
  • Это ссылка, которая помогла решить мою проблему: github.com/facebook/create-react-app/blob/master/packages/ jimbotron 10.07.2018

reactjsurljavascriptreact-router

Ответы

Ответ 1 · рейтинг 1410 · Stijn de Witt

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

На стороне сервера или на стороне клиента

Первое, что нужно понять, это то, что теперь есть 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 выполняет маршрутизацию за вас, но они не работают на стороне сервера, если вы не дадите своему серверу понять их.

Комбинирование маршрутизации на стороне сервера и на стороне клиента

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

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

.

Полный обход проблемы: история хеширования

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

Минусы:

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

.

Поймать все

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

Минусы:

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

.

Гибридный

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

Минусы:

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

.

Изоморфный

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

Минусы:

  • Сервер должен (уметь) запускать JS. Я экспериментировал с Java i.c.w. Нашорн, но у меня это не работает. На практике это в основном означает, что вы должны использовать сервер на основе Node JS.
  • Множество сложных экологических проблем (использование window на стороне сервера и т. Д.)
  • Крутая кривая обучения

.

Что мне использовать?

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

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

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

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

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

  • Выберите свой идеальный стартовый проект React

Я начал с этих:

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

Удачи в поисках!

Ответ 2 · рейтинг 154 · jmancherje

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

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

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

РЕДАКТИРОВАТЬ: см. Мой ответ здесь, чтобы подробнее узнать, почему это необходимо: https://stackoverflow.com/a/37622953/5217568

Ответ 3 · рейтинг 140 · BrahimS

Вы можете изменить свой .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>

Я использую react: "^16.12.0" и react-router: "^5.1.2". Этот метод является универсальным и, вероятно, является самым простым способом начать работу.

Ответ 4 · рейтинг 81 · user2875289

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

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

<Router history={hashHistory} >

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

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

<HashRouter>
  <App/>
</HashRouter>

Ссылка: HashRouter

Ответ 5 · рейтинг 48 · Aidin

Я только что использовал приложение create-react-app для создания веб-сайта, и у меня возникла та же проблема, что и здесь. Я использую 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, и его можно найти здесь

Ответ 6 · рейтинг 35 · Efe Ariaroo

В свой index.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 · рейтинг 32 · Todd

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

Когда вы используете компонент React Router Link, он блокирует навигацию браузера и вызывает transitionTo для выполнения навигации на стороне клиента. Вы используете 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-код на стороне сервера по мере необходимости.

Ответ 8 · рейтинг 27 · Colton Hicks

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

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

/*  /index.html  200

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

Ответ 9 · рейтинг 26 · th3morg

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

Эта проблема возникла из-за того, что CloudFront ответил сообщением 403 Access Denied, потому что ожидалось, что / some / other / path будет существовать в моей папке S3, но этот путь существует только внутри маршрутизации React с помощью response-router.

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

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

Ответ 10 · рейтинг 23 · Venkatesh Somu

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

Я также столкнулся с той же проблемой в приложении 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,

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

Вам нужно создать файл conf, чтобы решить страницу 404 not found, файл 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 service apache2 reload или перезапустить

затем откройте папку 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 · рейтинг 19 · Chtiwi Malek

Если вы размещаете свое приложение для реагирования на 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 и не использовать историю хеширования.

Ответ 12 · рейтинг 17 · sree

У Webpack Dev Server есть возможность включить это. Откройте package.json и добавьте --history-api-fallback. Эти решения сработали для меня.

response-router- руководство

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы