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 не нужно ничего запрашивать ни на каком сервере.
если вы не используете 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
Глядя на комментарии к принятому ответу и общий характер этого вопроса ("не работает"), я подумал, что это может быть хорошим местом для некоторых общих объяснений по затронутым здесь вопросам. Итак, этот ответ предназначен в качестве справочной информации / уточнения конкретного варианта использования 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, есть несколько хороших руководств по этой теме:
Как реализовать изоморфный JavaScript для Node + React и почему это важно
Кроме того, для начала я рекомендую посмотреть несколько стартовых комплектов. Выберите тот, который соответствует вашему выбору для стека технологий (помните, React - это просто V в MVC, вам нужно больше материала для создания полноценного приложения). Начнем с того, что опубликовал сам Facebook:
HistoryApiFallback - это то, что решило эту проблему для меня. Теперь маршрутизация работает правильно, и я могу обновить страницу или ввести URL-адрес напрямую. Не нужно беспокоиться об обходных методах на вашем сервере узлов. Этот ответ, очевидно, работает только в том случае, если вы используете веб-пакет.
Я только что использовал приложение create-react-app для создания веб-сайта, и у меня возникла та же проблема, что и здесь. Я использую BrowserRouting из пакета react-router-dom. Я работаю на сервере Nginx, и для меня это решило добавление следующего в /etc/nginx/yourconfig.conf
Это также кажется решением, предложенным самим 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-адреса и переходит к желаемому маршруту.