Реагирующий маршрутизатор не работает в ведре aws s3

Я развернул папку build/ моего веб-сайта React в корзине AWS S3.

Если я перейду на www.mywebsite.com, он сработает, и если я нажму на тег a, чтобы перейти на страницы Project и About, он приведет меня на нужную страницу. Однако, если я скопирую и отправлю URL-адрес страницы или перейду прямо по ссылке, например: www.mywebsite.com/projects, он вернет 404.

Вот мой код App.js:

const App = () => (
    <Router>
        <div>
            <NavBar/>
            <Switch>
                <Route exact path = "/" component = {Home}/>
                <Route exact path = "/projects" component = {Projects}/>
                <Route exact path = "/about" component = {About}/>
                <Route component = {NoMatch}/>
            </Switch>
        </div>
    </Router>
);

Я не думаю, что это проблема с React Router, скорее, ваш сервер не обслуживает ваши index.html и bundle.js по какому-либо другому маршруту, кроме /. Он должен обслуживать эти файлы на всех маршрутах.

Tholle 07.07.2018 02:26

Возможный обман stackoverflow.com/a/23544903/5079258. Вам нужно перенаправить ошибки (в данном случае 404) в корень index.html

Alan Friedman 07.07.2018 02:34
Поведение ключевого слова "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) для оценки ваших знаний,...
100
2
43 007
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Почему так происходит

Ваша проблема в том, что вы хотите передать ответственность за маршрутизацию своему реагирующему приложению / javascript. Ссылка будет работать, потому что react может прослушивать щелчок по ссылке и просто обновлять маршрут в адресной строке браузера. Однако, если вы перейдете в место, где ваш скрипт (index.html и bundle.js или где находится код вашего приложения) не загружен, то JavaScript никогда не загружается и не имеет возможности обработать запрос. Вместо этого, независимо от того, что запускает ваш сервер, он позаботится о запросе, посмотрит, есть ли в этом месте ресурс, и вернет ошибку 404 или что-то еще, что он обнаружил.

Решение

Как упоминалось в комментариях, это причина, по которой вам нужно перенаправить 404-ошибки в точное место, где размещено ваше приложение. В этом нет ничего специфического для Amazon, это общее требование для настройки вашего приложения для реагирования.

Чтобы решить эту проблему, вам нужно выяснить, что обрабатывает маршрутизацию на вашем сервере и как ее настроить. Например, если у вас есть сервер Apache, файл .htaccess может решить эту проблему следующим образом:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>

Этот файл позволяет серверу перенаправлять ненайденные ошибки в index.html. Имейте в виду, что это может повлиять на другие правила маршрутизации, которые есть на вашем сервере, поэтому эта конфигурация является самой простой, если ваше приложение для реагирования имеет собственное место, не мешая другим вещам.

Значит, я получаю http-запрос каждый раз, когда нажимаю ссылку в React?

Itay Moav -Malimovka 05.08.2019 04:52

@ ИтайМоав-Малимовка Нет, дело не в этом. Это происходит только после того, как вы введете приложение / введите исходный URL-адрес. Здесь сервер решает, что передать клиенту - в данном случае приложение React. С этого момента маршрутизатор React вступает во владение, изменяя отображаемый URL, историю и т.д. без ведома сервера.

Gegenwind 06.08.2019 11:10

это про маршрутизацию на s3. нет сервера между

mithril_knight 03.04.2020 20:23

Я не уверен, что вы уже решили это. Я была такая же проблема.

Это потому, что AWS S3 ищет ту папку (проекты) для обслуживания, которой у вас нет.

Просто укажите в документе об ошибке index.html.

Это сработало для меня. Вы можете обрабатывать страницы ошибок в response-router.

Спасибо, AR. Да, я решил это благодаря приведенному выше комментарию Алана Фридмана.

Viet 15.09.2018 17:34

маленькие вещи. когда я нажимаю путь, в консоли появляется сообщение «404 не найдено», поскольку мы перенаправляем его на страницу с ошибкой. Я не уверен. Может быть способ получше.

A.R Naseef 27.09.2018 14:19

Это тоже сработало для меня, но не думаете ли вы, что мы должны вместо этого применять правила перенаправления? Я пока не знаю, как это сделать. Я все еще изучаю это.

Basit 23.10.2018 09:43

Вы имеете в виду добавление правил перенаправления в aws S3?

A.R Naseef 27.10.2018 23:49

Это неправильный ответ ... поскольку у вас будет еще одна ошибка, проверьте этот вопрос: stackoverflow.com/questions/59160472/…

chemitaxis 03.12.2019 17:24

Да. Очевидно, это взлом. Для правильного решения вам может потребоваться добавить правила перенаправления S3. Также попробуйте использовать HashRouter (вместо BrowserRouter) из response-router. Это может сработать

A.R Naseef 05.12.2019 10:32

Хотя это решение работает, оно влияет на SEO. Google оценит ваш сайт хуже, чем другие, которые не так много 404. Я усвоил это на собственном горьком опыте.

Luis Gouveia 31.07.2020 13:05

@LuisGouveia, как вы тогда продвинулись? что ты сделал?

sumanth shetty 11.11.2020 08:52

@sumanthshetty проверьте мой комментарий к ответу "Амр Абу Грида"! Хорошего дня

Luis Gouveia 11.11.2020 09:04
Ответ принят как подходящий

Update 1 May 2020:

Поскольку этот пост довольно активен, мне нужно обновить ответ:

Итак, у вас есть несколько вариантов решения проблемы:

  1. Вы можете поместить index.html в поле Документ об ошибке (как предложил Алан Фридман).
    • Перейдите в свою корзину (ту, в которой на самом деле есть код, а не ту, которую вы используете для перенаправления) -> Характеристики -> Статический хостинг веб-сайтов:
    • Это не "хакерство", но работает из-за способа react-router работает: он обрабатывает запросы от внешнего интерфейса и направляет пользователей на другие маршруты, но в целом приложение React является одностраничным заявление.
    • Если вы хотите React на стороне сервера, подумайте об использовании Next.js.

  1. Вы можете поместить указанный файл ошибки error.html в папку общественный вашего приложения React и в поле Статический хостинг веб-сайтов: Документ об ошибке, вставив: error.html. Это тоже работает. Я это проверил.

  2. Используйте AWS CloudFront> Распределения CloudFront> Распределение вашего ведра> Страницы ошибок и добавьте нужный код ошибки. Если вы не используете react-router (как в примере ниже), корзина ответит Ошибка 403, так что вы можете ответить своим error.html.

  1. Для TypeScript в настоящее время react-router не поддерживает его, поэтому вам следует рассмотреть вариант 2 и 3. Они собираются обновить библиотеку в будущей версии 6.* согласно эта ветка.

Это очень хакерское решение, но я тоже использую его. Что мне не нравится в этом, так это то, что 404 все еще происходит, его просто перенаправляют.

ThisGuyCantEven 12.08.2019 18:51

Имейте в виду одно из последствий этого ... если ваша веб-страница включает src = "/static/somescript.js", где somescript.js на самом деле не существует, или где доступ к запрошенному сценарию запрещен, тогда запрос браузера выдаст содержимое файла index.html а не файл JS, и он будет анализироваться браузером как JavaScript и приведет к ошибкам синтаксического анализа JavaScript «<! doctype html> ...». Аналогично для файлов CSS или других ресурсов.

jarmod 26.12.2019 23:33

Это решение влияет на SEO. Google не очень хорошо ранжирует сайты, выдающие ошибку 404.

Luis Gouveia 31.07.2020 13:09

Я столкнулся с этой проблемой, несмотря на использование конфигурации, описанной в принятом ответе, но если вы по-прежнему получаете ошибку 403, И вы используете AWS Cloudflare Manager, вы можете создать страницу с ошибкой на вкладке «Страницы ошибок» в настройках распространения. , со следующей конфигурацией:

Error Code: 404,
Customize Error Response: Yes, 
Response Page Path: /index.html, 
HTTP Response Code: 200

Изображение конфигурации страницы ошибок для передачи обработки маршрута маршрутизатору браузера

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

403 = запрещено. Вы уверены, что ваша корзина или объект являются общедоступными?

Viet 08.03.2019 15:45

Я сделал то же самое, что и @worc: CloudFront> Страницы ошибок> Создать собственный ответ об ошибке> 403 или 404, в зависимости от вашей ошибки> Настроить ответ при ошибке: Да> Путь к странице ответа: /index.html> Код ответа HTTP: 200

Sven Möhring 08.10.2019 13:50

У вас будет в облаке ошибка x-cache error из cloudfront

chemitaxis 03.12.2019 17:23

Вариант использования Cloudfront для S3:

https://hackernoon.com/hosting-static-react-websites-on-aws-s3-cloudfront-with-ssl-924e5c134455

3b) AWS CloudFront - страницы ошибок После создания раздачи CloudFront, когда он находится в состоянии «Выполняется», перейдите на вкладку «Страницы ошибок». Обрабатывайте коды ответов 404 и 403 с помощью настройки ответа на ошибку.

Google рекомендует 1 неделю или 604800 секунд кеширования. Здесь мы настраиваем CloudFront для обработки отсутствующих html-страниц, что обычно происходит, когда пользователь вводит недопустимый путь или, в частности, когда они обновляют путь, отличный от корневого.

Когда это произойдет:

CloudFront будет искать файл, которого нет в корзине S3; в корзине только 1 html-файл, и это index.html для случая одностраничного приложения, такого как этот пример проекта. Будет возвращен ответ 404, и наша настраиваемая настройка ответа на ошибку захватит его. Вместо этого мы вернем код ответа 200 и страницу index.html. Маршрутизатор React, который будет загружен вместе с файлом index.html, будет смотреть на URL-адрес и отображать правильную страницу вместо корневого пути. Эта страница будет кешироваться на время TTL для всех запросов к запрошенному пути. Почему нам также нужно обрабатывать 403? Это связано с тем, что этот код ответа вместо 404 возвращается Amazon S3 для активов, которых нет. Например, URL-адрес https://yourdomain.com/somewhere будет искать файл, названный где-то (без расширения), который не существует.

PS. Раньше он возвращал 404, но теперь кажется, что он возвращает 403; в любом случае лучше обрабатывать оба кода ответа).

Это сработало для меня. То же, что и stackoverflow.com/a/52343542/2624935, но для облачного фронта.

Pnar Sbi Wer 11.07.2019 03:14

Это сработало! Просмотрено множество статей об этом 403 - это недостающее звено - спасибо

Chris Webb 13.11.2019 09:53

Вопреки тому, что говорится в статье, это относится не только к HTML-страницам. Любая ошибка 404, в том числе для изображений и т. д., Будет перенаправлять index.html, что довольно некрасиво.

cbp 20.08.2020 04:10

В случае, если этот сегмент S3 обслуживается из Распространение CloudFront:

Создайте настраиваемая страница ошибок (AWS Docs) в раздаче CloudFront, который направляет ошибку 404 в index.html и возвращает код ответа 200. Таким образом ваше приложение будет обрабатывать маршрутизацию.

Пользовательские страницы ошибок

ДА, мне тоже пришлось добавить 403

arthurakay 22.07.2020 02:30

Разве это не привело бы к нежелательному поведению маршрутизации законных 404-х сообщений в index.html, в том числе для изображений и т. д.? Иногда вам действительно нужен настоящий 404-й.

cbp 20.08.2020 03:56

Это идея, лежащая в основе «ваше приложение будет управлять маршрутизацией». Каждый запрос проходит через ваш index.html (одностраничное приложение), и маршрутизатор вашего приложения возвращает соответствующий ответ. Это означает, что вы сохраняете логику маршрутизации в самом приложении, избегая обслуживания другой логики маршрутизации в CloudFront. Это просто приятный трюк, который упрощает жизнь разработчика - маршрутизация как единое окно, не нужно ничего знать об AWS.

Meir Gabay 20.08.2020 09:29

Ну, за исключением того, что ваше приложение в этом случае является клиентским, а не серверным. Таким образом, как «приложение» вы больше не можете сигнализировать о том, что ресурс не найден. Я считаю, что вам следует различать маршруты и файлы, которые будут обрабатываться приложением, и маршруты, которые будут обрабатываться S3 или cloudfront.

froginvasion 20.08.2020 12:25

Согласно предыдущим ответам, лучший способ решить проблему: переопределить запасную стратегию. Если вы хотите узнать больше о маршрутизации на стороне клиента и на стороне сервера, и особенно о различных подходах к маршрутизации в React JS, ознакомьтесь с эта статья.

Это решение, похоже, страдает от нескольких проблем: 1) Хотя содержимое страницы возвращается правильно, код ответа http по-прежнему 404. 2) Он захватывает 404 запроса на такие вещи, как изображения и т. д., И перенаправляет их на index.html.

cbp 20.08.2020 03:52

Хороший звонок, если это проблема, я бы предложил использовать правила перенаправления Правила перенаправления. На одну строку ниже конфигурации страницы ошибки. Пример 3: Перенаправление при ошибке HTTP из документа будет хорошей отправной точкой. В части <Condition> мы можем добавить что-то вроде <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEqual‌​s>. И всех запросов должно быть 301.

Val 23.08.2020 02:35

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

S3 имеет два типа конечных точек, и если вы столкнулись с этой ошибкой, вы, вероятно, выбрали сегмент S3 непосредственно в качестве конечной точки в поле «Имя исходного домена» для вашего распространения CloudFront.

Это будет выглядеть примерно так: bucket-name.s3.amazonaws.com и является вполне допустимой конечной точкой. Фактически, может показаться, что AWS действительно ожидает такого поведения по умолчанию; эта запись будет в раскрывающемся списке, который будет у вас при создании раздачи CloudFront.

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

Однако у S3 есть выделенная конечная точка веб-сайта. Это доступно в вашем сегменте S3> Свойства> Статический хостинг веб-сайтов. (Вы увидите ссылку вверху).

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

Эта ссылка будет выглядеть так: bucket-name.s3-website.region-name.amazonaws.com.

Как только это распространится и изменится, это должно решить вашу проблему.

tl; dr: не используйте конечную точку S3 по умолчанию в CloudFront. Вместо этого используйте конечную точку веб-сайта S3. Ваш исходный домен должен выглядеть так: my-application.s3-website.us-east-1.amazonaws.com, а не my-application.s3.amazonaws.com.

Дополнительная информация о конечных точках веб-сайтов доступна в документации AWS здесь.

Это работает. Но тогда зачем вам облачный фронт и преимущества SSL и многорегионального распространения?

Patrick Bassut 11.12.2020 04:23

Перенаправление 4xx на index.html будет работать, но это решение может вызвать у вас множество других проблем, например, Google не сможет сканировать эти страницы. Пожалуйста, проверьте эта ссылка, он решил эту проблему с помощью правил перенаправления для корзины S3.

Ваш ответ потрясающий! Это должен быть принятый ответ, поскольку принятый вариант является неоптимальным и оказывает очень неудобное влияние на SEO (потому что Google не любит сайты, возвращающие 404-е). Если кто-то ищет эквивалент @Amr Abu Greedah для мира Microsoft, я рекомендую проверить следующий ответ: stackoverflow.com/a/50767709/3231884

Luis Gouveia 31.07.2020 15:08

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

Nick 30.11.2020 21:01

Однозначно правильный ответ. Я слишком долго искал этот путь.

Dean Koštomaj 04.04.2021 09:09

обновить конфигурацию s3 со статическим хостингом и по умолчанию с index.html введите описание изображения здесь

добавить CloudFront со страницей ошибок

404 error-> index.html->status 200

введите описание изображения здесь

Я исправил это, используя HashRouter вместо Router

import { Switch, Route, HashRouter } from 'react-router-dom';

const App = () => (
    <HashRouter>
        <div>
            <NavBar/>
            <Switch>
                <Route exact path = "/" component = {Home}/>
                <Route exact path = "/projects" component = {Projects}/>
                <Route exact path = "/about" component = {About}/>
                <Route component = {NoMatch}/>
            </Switch>
        </div>
    </HashRouter>
);

Приложение поддерживает что-то вроде https://your-domain.s3.amazonaws.com/index.html?someParam=foo&otherPram=bar/#/projects

на локальном хосте, как https://localhost:3000/?someParam=foo&otherPram=bar/#/projects

Никаких изменений в S3 не потребовалось.

Похоже на быстрое и изящное решение. Но будьте осторожны! в своей документации они рекомендуют вместо этого настроить ваш сервер: «ВАЖНОЕ ПРИМЕЧАНИЕ: история хеширования не поддерживает location.key или location.state. В предыдущих версиях мы пытались изменить поведение, но были крайние случаи, которые мы не могли решить. Любые код или подключаемый модуль, которому требуется такое поведение, не будет работать. Поскольку этот метод предназначен только для поддержки устаревших браузеров, мы рекомендуем вам настроить сервер для работы с <BrowserHistory> вместо этого ». reactrouter.com/web/api/HashRouter

wojjas 20.11.2020 09:34

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

const router = useRouter();
useEffect(() => {
    if (!router.pathname.startsWith(router.asPath)) {
      router.push(router.asPath);
    }
  });

На стороне S3 ничего не нужно было изменять, кроме перенаправления страницы с ошибкой в ​​index.html.

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

Фрагмент кода добавляет index.html в качестве страницы ошибки в s3, а также в облачном интерфейсе. В частности, для облачного интерфейса я добавил страницу ошибки как /index.html для 404 и 403 с ответом 200.


// imports...
// import * as cdk from '@aws-cdk/core';
// import * as s3 from '@aws-cdk/aws-s3';
// import * as cloudfront from '@aws-cdk/aws-cloudfront';

// following code snippet has to be added in a 
// class which extends to a Construct or a Stack

    const bucket = new s3.Bucket(this, '<Specify a name>', {
      bucketName: '<add your bucket name>',
      websiteIndexDocument: 'index.html',
      websiteErrorDocument: 'index.html',
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // edit it according to your use case, I'll change it though
      autoDeleteObjects: true,
    });

    const cloudFrontOAI = new cloudfront.OriginAccessIdentity(this, 'OAI');

    const distribution = new cloudfront.CloudFrontWebDistribution(this, props?.stackName + 'AbcWebsiteDistribution', {
      defaultRootObject: "index.html",
      errorConfigurations: [{
        errorCode: 404,
        responsePagePath: "/index.html",
        responseCode: 200
      }, {
        errorCode: 403,
        responsePagePath: "/index.html",
        responseCode: 200
      }],
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: bucket,
            originAccessIdentity: cloudFrontOAI,
            originPath: "/artifacts" // change this based on your use case
          },
          behaviors: [{ isDefaultBehavior: true }]
        }
      ]
    })

    bucket.grantRead(cloudFrontOAI.grantPrincipal);

Ответы, которые мне действительно помогли из этой ветки:

https://stackoverflow.com/a/56655629/6211961

https://stackoverflow.com/a/58978355/6211961

https://stackoverflow.com/a/64201582/6211961

Ниже конфигурация решена

Обновлены страницы ошибок в соответствующем распределении облачного фронта с настраиваемым ответом об ошибке от кода состояния http 404-не найден до кода 200-OK в пути к странице ответа как / и почти нулевое время жизни

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