Я развернул папку 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>
);
Возможный обман stackoverflow.com/a/23544903/5079258. Вам нужно перенаправить ошибки (в данном случае 404) в корень index.html



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Почему так происходит
Ваша проблема в том, что вы хотите передать ответственность за маршрутизацию своему реагирующему приложению / 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?
@ ИтайМоав-Малимовка Нет, дело не в этом. Это происходит только после того, как вы введете приложение / введите исходный URL-адрес. Здесь сервер решает, что передать клиенту - в данном случае приложение React. С этого момента маршрутизатор React вступает во владение, изменяя отображаемый URL, историю и т.д. без ведома сервера.
это про маршрутизацию на s3. нет сервера между
Я не уверен, что вы уже решили это. Я была такая же проблема.
Это потому, что AWS S3 ищет ту папку (проекты) для обслуживания, которой у вас нет.
Просто укажите в документе об ошибке index.html.
Это сработало для меня. Вы можете обрабатывать страницы ошибок в response-router.
Спасибо, AR. Да, я решил это благодаря приведенному выше комментарию Алана Фридмана.
маленькие вещи. когда я нажимаю путь, в консоли появляется сообщение «404 не найдено», поскольку мы перенаправляем его на страницу с ошибкой. Я не уверен. Может быть способ получше.
Это тоже сработало для меня, но не думаете ли вы, что мы должны вместо этого применять правила перенаправления? Я пока не знаю, как это сделать. Я все еще изучаю это.
Вы имеете в виду добавление правил перенаправления в aws S3?
Это неправильный ответ ... поскольку у вас будет еще одна ошибка, проверьте этот вопрос: stackoverflow.com/questions/59160472/…
Да. Очевидно, это взлом. Для правильного решения вам может потребоваться добавить правила перенаправления S3. Также попробуйте использовать HashRouter (вместо BrowserRouter) из response-router. Это может сработать
Хотя это решение работает, оно влияет на SEO. Google оценит ваш сайт хуже, чем другие, которые не так много 404. Я усвоил это на собственном горьком опыте.
@LuisGouveia, как вы тогда продвинулись? что ты сделал?
@sumanthshetty проверьте мой комментарий к ответу "Амр Абу Грида"! Хорошего дня
Update 1 May 2020:
Поскольку этот пост довольно активен, мне нужно обновить ответ:
Итак, у вас есть несколько вариантов решения проблемы:
react-router
работает: он обрабатывает запросы от внешнего интерфейса и направляет пользователей на
другие маршруты, но в целом приложение React является одностраничным
заявление.Вы можете поместить указанный файл ошибки error.html в папку общественный вашего приложения React и в поле Статический хостинг веб-сайтов: Документ об ошибке, вставив: error.html. Это тоже работает. Я это проверил.
Используйте AWS CloudFront> Распределения CloudFront> Распределение вашего ведра> Страницы ошибок и добавьте нужный код ошибки. Если вы не используете react-router (как в примере ниже), корзина ответит Ошибка 403, так что вы можете ответить своим error.html.
TypeScript в настоящее время react-router не поддерживает его, поэтому вам следует рассмотреть вариант 2 и 3. Они собираются обновить библиотеку в будущей версии 6.* согласно эта ветка.Это очень хакерское решение, но я тоже использую его. Что мне не нравится в этом, так это то, что 404 все еще происходит, его просто перенаправляют.
Имейте в виду одно из последствий этого ... если ваша веб-страница включает src = "/static/somescript.js", где somescript.js на самом деле не существует, или где доступ к запрошенному сценарию запрещен, тогда запрос браузера выдаст содержимое файла index.html а не файл JS, и он будет анализироваться браузером как JavaScript и приведет к ошибкам синтаксического анализа JavaScript «<! doctype html> ...». Аналогично для файлов CSS или других ресурсов.
Это решение влияет на SEO. Google не очень хорошо ранжирует сайты, выдающие ошибку 404.
Я столкнулся с этой проблемой, несмотря на использование конфигурации, описанной в принятом ответе, но если вы по-прежнему получаете ошибку 403, И вы используете AWS Cloudflare Manager, вы можете создать страницу с ошибкой на вкладке «Страницы ошибок» в настройках распространения. , со следующей конфигурацией:
Error Code: 404,
Customize Error Response: Yes,
Response Page Path: /index.html,
HTTP Response Code: 200
Изображение конфигурации страницы ошибок для передачи обработки маршрута маршрутизатору браузера
Это сработало для меня, хотя я никоим образом не разбираюсь в правильном администрировании сервера, надеюсь, кто-нибудь скажет мне, является ли это серьезной проблемой, если это будет случайность.
403 = запрещено. Вы уверены, что ваша корзина или объект являются общедоступными?
Я сделал то же самое, что и @worc: CloudFront> Страницы ошибок> Создать собственный ответ об ошибке> 403 или 404, в зависимости от вашей ошибки> Настроить ответ при ошибке: Да> Путь к странице ответа: /index.html> Код ответа HTTP: 200
У вас будет в облаке ошибка x-cache error из cloudfront
Вариант использования 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, но для облачного фронта.
Это сработало! Просмотрено множество статей об этом 403 - это недостающее звено - спасибо
Вопреки тому, что говорится в статье, это относится не только к HTML-страницам. Любая ошибка 404, в том числе для изображений и т. д., Будет перенаправлять index.html, что довольно некрасиво.
В случае, если этот сегмент S3 обслуживается из Распространение CloudFront:
Создайте настраиваемая страница ошибок (AWS Docs) в раздаче CloudFront, который направляет ошибку 404 в index.html и возвращает код ответа 200. Таким образом ваше приложение будет обрабатывать маршрутизацию.
ДА, мне тоже пришлось добавить 403
Разве это не привело бы к нежелательному поведению маршрутизации законных 404-х сообщений в index.html, в том числе для изображений и т. д.? Иногда вам действительно нужен настоящий 404-й.
Это идея, лежащая в основе «ваше приложение будет управлять маршрутизацией». Каждый запрос проходит через ваш index.html (одностраничное приложение), и маршрутизатор вашего приложения возвращает соответствующий ответ. Это означает, что вы сохраняете логику маршрутизации в самом приложении, избегая обслуживания другой логики маршрутизации в CloudFront. Это просто приятный трюк, который упрощает жизнь разработчика - маршрутизация как единое окно, не нужно ничего знать об AWS.
Ну, за исключением того, что ваше приложение в этом случае является клиентским, а не серверным. Таким образом, как «приложение» вы больше не можете сигнализировать о том, что ресурс не найден. Я считаю, что вам следует различать маршруты и файлы, которые будут обрабатываться приложением, и маршруты, которые будут обрабатываться S3 или cloudfront.
Согласно предыдущим ответам, лучший способ решить проблему: переопределить запасную стратегию. Если вы хотите узнать больше о маршрутизации на стороне клиента и на стороне сервера, и особенно о различных подходах к маршрутизации в React JS, ознакомьтесь с эта статья.
Это решение, похоже, страдает от нескольких проблем: 1) Хотя содержимое страницы возвращается правильно, код ответа http по-прежнему 404. 2) Он захватывает 404 запроса на такие вещи, как изображения и т. д., И перенаправляет их на index.html.
Хороший звонок, если это проблема, я бы предложил использовать правила перенаправления Правила перенаправления. На одну строку ниже конфигурации страницы ошибки. Пример 3: Перенаправление при ошибке HTTP из документа будет хорошей отправной точкой. В части <Condition> мы можем добавить что-то вроде <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>. И всех запросов должно быть 301.
На этот вопрос уже есть несколько отличных ответов. Хотя вопрос сейчас старый, я столкнулся с этой проблемой сегодня, поэтому я чувствую, что, возможно, этот ответ может помочь.
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 и многорегионального распространения?
Перенаправление 4xx на index.html будет работать, но это решение может вызвать у вас множество других проблем, например, Google не сможет сканировать эти страницы. Пожалуйста, проверьте эта ссылка, он решил эту проблему с помощью правил перенаправления для корзины S3.
Ваш ответ потрясающий! Это должен быть принятый ответ, поскольку принятый вариант является неоптимальным и оказывает очень неудобное влияние на SEO (потому что Google не любит сайты, возвращающие 404-е). Если кто-то ищет эквивалент @Amr Abu Greedah для мира Microsoft, я рекомендую проверить следующий ответ: stackoverflow.com/a/50767709/3231884
На всякий случай, если использование формата xml не удается, попробуйте использовать версию json для правил перенаправления. Вот что мне нужно было сделать, чтобы это решение работало на меня.
Однозначно правильный ответ. Я слишком долго искал этот путь.
обновить конфигурацию 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
Я использую 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
Я не думаю, что это проблема с React Router, скорее, ваш сервер не обслуживает ваши
index.htmlиbundle.jsпо какому-либо другому маршруту, кроме/. Он должен обслуживать эти файлы на всех маршрутах.