Хостинг статического веб-сайта S3. Все пути к Index.html.


250

Я использую S3 для размещения приложения JavaScript, которое будет использовать push5tates HTML5. Проблема в том, что если пользователь добавит в закладки какой-либо из URL-адресов, он ни к чему не приведет. Что мне нужно, так это возможность принимать все URL-запросы и обслуживать корневой index.html в моем контейнере S3, а не просто выполнять полное перенаправление. Тогда мое приложение javascript могло бы проанализировать URL и предоставить нужную страницу.

Есть ли какой-нибудь способ сказать S3 обслуживать index.html для всех URL-запросов вместо того, чтобы делать перенаправления? Это было бы похоже на настройку apache для обработки всех входящих запросов путем предоставления одного index.html, как в этом примере: https://stackoverflow.com/a/10647521/1762614 . Я действительно хотел бы избежать запуска веб-сервера только для обработки этих маршрутов. Делать все из S3 очень привлекательно.


Вы нашли решение для этого?
w2lame

Ответы:


302

С помощью CloudFront очень легко решить эту проблему без URL-хаков.

  • Создайте S3 Bucket, например: реагировать
  • Создайте дистрибутивы CloudFront со следующими настройками:
    • Корневой объект по умолчанию : index.html
    • Исходное доменное имя : S3 bucket domain, например: react.s3.amazonaws.com
  • Перейдите на вкладку « Страницы ошибок », нажмите « Создать пользовательский ответ об ошибке» :
    • Код ошибки HTTP : 403: запрещено (404: не найдено, в случае статического веб-сайта S3)
    • Настройка ответа об ошибке : Да
    • Путь к странице ответа : /index.html
    • Код ответа HTTP : 200: ОК
    • Нажмите на Создать

8
Спасибо. Лучший ответ на данный момент.
JGB

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

5
для меня это сработало как чудо, только нужный мне код ошибки был 404, а не 403
Джереми С.

4
Немного хак, но прекрасно работает :) Было бы неплохо, если бы CloudFront просто позволил нам отобразить диапазон путей к файлу S3 (без перенаправления).
Боб

3
Это не работает для меня. Это решение всегда перенаправляет на домашнюю страницу, а не на правильные страницы ...
Джим

201

Я смог заставить это работать следующим образом:

В разделе « Изменить правила перенаправления» консоли S3 для своего домена добавьте следующие правила:

<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>yourdomainname.com</HostName>
      <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
    </Redirect>
  </RoutingRule>
</RoutingRules>

Это перенаправит все пути, в результате которых 404 не найден в ваш корневой домен с версией хеш-взрыва пути. Поэтому http://yourdomainname.com/posts будет перенаправлять на http://yourdomainname.com/#!/posts при условии, что в / posts отсутствует файл.

Однако, чтобы использовать pushStates в HTML5, нам нужно принять этот запрос и вручную установить правильное pushState на основе пути хеш-взрыва. Так что добавьте это в начало вашего файла index.html:

<script>
  history.pushState({}, "entry page", location.hash.substring(1));
</script>

Это захватывает хэш и превращает его в push5-состояние HTML5. С этого момента вы можете использовать pushStates, чтобы в вашем приложении были пути без хэша.


4
Это решение прекрасно работает! Фактически angularjs будет автоматически делать историю pushState, если настроен режим html.
wcandillon

1
Это потерпит неудачу со старой версией IE, если в ваши URL включены параметры GET, правильно? Как вы справляетесь с этой проблемой?
Клексмонд

3
Спасибо! Это работало хорошо для меня на позвоночнике с небольшой настройкой. Я добавил в чеке для старых браузеров: <script language="javascript"> if (typeof(window.history.pushState) == 'function') { window.history.pushState(null, "Site Name", window.location.hash.substring(2)); } else { window.location.hash = window.location.hash.substring(2); } </script>
AE Grey

10
Успешно с react-routerэтим решением, используя push5tates HTML5 и<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
Феликс Д.

5
Он не работает в сафари и является большой проблемой в стратегии развертывания. Написание небольшого js для перенаправления - довольно потрепанный подход. Кроме того, количество перенаправлений также является проблемой. Я пытаюсь понять, есть ли способ для всех URL-адресов S3 всегда указывать на index.html.
moha297

129

Есть несколько проблем с подходом на основе S3 / Redirect, упомянутых другими.

  1. Перенаправления Mutliple происходят при разрешении путей вашего приложения. Например: www.myapp.com/path/for/test перенаправляется как www.myapp.com/#/path/for/test
  2. В строке URL появляется мерцание, когда «#» появляется и уходит из-за действия вашей структуры SPA.
  3. На SEO влияет, потому что - «Эй! Гугл заставляет его перенаправлять руку
  4. Поддержка Safari для вашего приложения требует больших усилий.

Решение:

  1. Убедитесь, что у вас настроен индексный маршрут для вашего сайта. В основном это index.html
  2. Удалить правила маршрутизации из конфигураций S3
  3. Поместите Cloudfront перед вашей корзиной S3.
  4. Настройте правила страницы ошибок для своего экземпляра Cloudfront. В правилах ошибок укажите:

    • Http код ошибки: 404 (и 403 или другие ошибки по необходимости)
    • Минимальный TTL кэширования ошибок (секунд): 0
    • Настроить ответ: Да
    • Путь к странице ответа: /index.html
    • Код ответа HTTP: 200

      1. Для нужд SEO +, убедившись, что ваш index.html не кэшируется, сделайте следующее:
    • Сконфигурируйте экземпляр EC2 и настройте сервер nginx.

    • Назначьте публичный ip вашему экземпляру EC2.
    • Создайте ELB с экземпляром EC2, который вы создали в качестве экземпляра.
    • Вы должны быть в состоянии назначить ELB вашему DNS.
    • Теперь настройте сервер nginx на следующие действия: Proxy_pass все запросы к вашему CDN (только для index.html, обслуживайте другие ресурсы прямо из вашего облачного фронта) и для поисковых роботов, перенаправляйте трафик, как это предусмотрено службами, такими как Prerender.io

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

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


6
Так как S3 отвечает 403 Запрещено, когда файл не существует, я думаю, что шаг 4 выше должен быть продублирован для кода ошибки Http 403
Andreas

4
Для меня это единственный ответ, который приводит к ожидаемому (принятому) поведению
mabe.berlin

1
@ moha297 в пункте 5, вы в основном настраиваете свой сайт для выборки из nginx, который затем прокси из CDN (кроме запросов index.html и crawler)? Если это так, разве вы не потеряете преимущество пограничных серверов CDN?
Рахул Патель

2
@ moha297 Не могли бы вы объяснить этот комментарий: «Вы никогда не должны обслуживать index.html из CDN»? Я не вижу проблемы с обслуживанием index.html из S3 с CloudFront.
Карл Дж

1
См. Stackoverflow.com/a/10622078/4185989 для получения дополнительной информации о том, как обрабатывается TTL 0 (короткая версия: он кэшируется Cloudfront, но If-Modified-Sinceзапрос GET отправляется источнику) - может быть полезным для людей, не желающих настроить сервер как в шаге 5.
jmq

18

Это тангенциально, но вот совет для тех, кто использует библиотеку Rackt React Router с (HTML5) историей браузера и хочет разместить на S3.

Предположим, что пользователь заходит /foo/bearна ваш статический веб-сайт, размещенный на S3. Учитывая более раннее предложение Дэвида , правила перенаправления отправят их . Если ваше приложение построено с использованием истории браузера, это не принесет много пользы. Однако в этот момент ваше приложение загружено, и теперь оно может манипулировать историей./#/foo/bear

Включив историю Rackt в наш проект (см. Также раздел « Использование пользовательских историй из проекта React Router»), вы можете добавить прослушиватель, который знает пути к истории хеша, и при необходимости заменить путь, как показано в этом примере:

import ReactDOM from 'react-dom';

/* Application-specific details. */
const route = {};

import { Router, useRouterHistory } from 'react-router';
import { createHistory } from 'history';

const history = useRouterHistory(createHistory)();

history.listen(function (location) {
  const path = (/#(\/.*)$/.exec(location.hash) || [])[1];
  if (path) history.replace(path);
});

ReactDOM.render(
  <Router history={history} routes={route}/>,
  document.body.appendChild(document.createElement('div'))
);

Подведем итог:

  1. S3 правило редиректа Давида будет направлять /foo/bearна/#/foo/bear .
  2. Ваше приложение загрузится.
  3. Слушатель истории обнаружит #/foo/bearзапись истории.
  4. И замени историю на правильный путь.

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

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


2
Это помогло мне Майкл, спасибо! Вы можете изменить ссылку на историю и просто использовать BrowserHistory. то естьbrowserHistory.listen
Маршал Мутено

Пожалуйста! Рад помочь. Кроме того, согласовано, и для этого конкретного случая использования я обновил фрагмент, чтобы устранить предупреждение об устаревании от React Router.
Майкл Алерс

С выпуском реагировать маршрутизаторами v3.0.0 это не работает, потому что реагирует-маршрутизатор использует v3.0.0 История v3.0.0
Varand Пезешкиан

Любая идея, как предотвратить history.listen бесконечный цикл вызова? Вызвано заменой пути, я думаю.
Мирко Флайктман

14

Я вижу 4 решения этой проблемы. Первые 3 уже были охвачены в ответах, и последний - мой вклад.

  1. Установите документ об ошибке в index.html.
    Проблема : тело ответа будет правильным, но код состояния будет 404, что вредит SEO.

  2. Установите правила перенаправления.
    Проблема : URL-адрес загрязнен #!и страница мигает при загрузке.

  3. Настройте CloudFront.
    Проблема : все страницы будут возвращать 404 от источника, поэтому вам нужно выбрать, если вы не будете кэшировать что-либо (TTL 0 в соответствии с предложением) или если вы будете кэшировать и иметь проблемы при обновлении сайта.

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

Я предлагаю использовать вариант 4. Если вы предварительно отобразите все страницы, на ожидаемых страницах не будет 404 ошибок. Страница будет загружена нормально, а фреймворк получит контроль и будет действовать как SPA. Вы также можете настроить документ ошибок для отображения общей страницы error.html и правила перенаправления для перенаправления ошибок 404 на страницу 404.html (без хеш-бенга).

Что касается 403 Запрещенных ошибок, я не позволяю им случиться вообще. В моем приложении, я считаю , что все файлы в принимающем ведре являются открытыми , и я установить это с каждым вариантом с чтением разрешения. Если на вашем сайте есть страницы, которые являются частными, разрешение пользователю видеть макет HTML не должно быть проблемой. Вам нужно защитить данные, и это делается в бэкэнде.

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


1
и на вашем сайте есть отличный пример использования с prerender для всех страниц. zanon.io/posts/… .- Спасибо
frekele

Этот четвертый подход обращается к пользователю, перезагружающему URL pushState? Он отлично справляется с навигацией, но при перезагрузке он все равно достигает сервера.
Альфа

@ Альфа, я не уверен, правильно ли я понял твой вопрос, но при повторной загрузке он будет действовать как новый запрос. S3 получит запрос и снова вернет предварительно обработанную страницу. В этом случае нет сервера.
Занон

@Zanon Ах, я думаю, я понимаю. Я думал, что это должно было кэшировать предварительно обработанные страницы и избегать использования несуществующих ресурсов S3. Это исключило бы маршруты с динамическими элементами, верно?
Альфа

1
@Zanon Я наконец-то понимаю - спасибо! Да, это то, что я имел в виду. :)
Alpha

13

Сегодня я столкнулся с той же проблемой, но решение @ Mark-Nutter было неполным, чтобы удалить хэш-бэнг из моего приложения angularjs.

Фактически, вам нужно перейти в « Редактировать разрешения» , нажать « Добавить дополнительные разрешения», а затем добавить правильный список в вашем списке для всех. С этой конфигурацией AWS S3 теперь сможет возвращать ошибку 404, а затем правило перенаправления правильно поймает случай.

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

А затем вы можете перейти к « Изменить правила перенаправления» и добавить это правило:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <HostName>subdomain.domain.fr</HostName>
            <ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

Здесь вы можете заменить имя_узла subdomain.domain.fr своим доменом и KeyPrefix #! /, Если вы не используете метод hashbang для целей SEO.

Конечно, все это будет работать, только если у вас уже есть настройка html5mode в вашем угловом приложении.

$locationProvider.html5Mode(true).hashPrefix('!');

Моя единственная проблема в том, что у вас есть вспышка hashbang, которой у вас нет с чем-то вроде правила nginx. Пользователь находится на странице и обновляет: / products / 1 -> #! /
Products

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

11

Самым простым решением сделать приложение Angular 2+ из Amazon S3 и работающих прямых URL-адресов является указание index.html как документов Index и Error в конфигурации S3 Bucket.

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


11
Это тот же ответ этого сильно опущенного ответа . Работает нормально, но только для bodyответа. Код статуса будет 404, и это повредит SEO.
Занон

Потому что это работает только в том bodyслучае, если у вас есть какие-либо скрипты, которые вы импортируете в headних, они не будут работать, когда вы напрямую попадете на любой из суб-маршрутов на вашем сайте
Мохамед

4

так как проблема все еще существует, я, хотя и добавляю другое решение. Мой случай состоял в том, что я хотел автоматически развернуть все pull-запросы на s3 для тестирования перед слиянием, сделав их доступными на [mydomain] / pull-запросы / [pr номер] /
(например, www.example.com/pull-requests/822/ )

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

Поэтому я указал свой домен на свой сервер, где следующий конфиг nginx сделал свою работу

location /pull-requests/ {
    try_files $uri @get_files;
}
location @get_files {
    rewrite ^\/pull-requests\/(.*) /$1 break;
    proxy_pass http://<your-amazon-bucket-url>;
    proxy_intercept_errors on;
    recursive_error_pages on;
    error_page 404 = @get_routes;
}

location @get_routes {
    rewrite ^\/(\w+)\/(.+) /$1/ break;
    proxy_pass http://<your-amazon-bucket-url>;
    proxy_intercept_errors on;
    recursive_error_pages on;
    error_page 404 = @not_found;
}

location @not_found {
    return 404;
}

он пытается получить файл и, если не найден, предполагает, что это маршрут html5, и пытается это сделать. Если у вас есть угловая страница 404 для не найденных маршрутов, вы никогда не доберетесь до @not_found и получите угловую страницу 404, а не найденные файлы, которые можно исправить с помощью некоторого правила if в @get_routes или чего-то подобного.

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

Примечание : удалите правила перенаправления s3, если они были в конфигурации S3.

и кстати работает в сафари


привет .. спасибо за решение ... где вы положили этот файл Config nginx для развертывания S3. это то же самое, что и эластичный beanstalk, где мне нужно создать папку .exextensions и поместить ее в файл proxy.config?
user3124360

@ user3124360 Не уверен насчет эластичного бобового стека, но в моем случае я указываю свое доменное имя на экземпляр ec2, и в нем есть конфигурация nginx. Так что запрос идет КЛИЕНТ -> DNS -> EC2 -> S3 -> КЛИЕНТ.
Андрей Арнаутов

да, я делаю что-то очень похожее ... с конфигурацией nginx здесь github.com/davezuko/react-redux-starter-kit/issues/1099 ... спасибо за публикацию вашего файла conf .. я вижу, как разрабатывать этот EC2 -> S3 соединение сейчас
user3124360

3

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

Во-первых, у меня есть корзина s3 с несколькими папками, каждая папка представляет собой сайт реакции / редукции. Я также использую cloudfront для аннулирования кэша.

Поэтому мне пришлось использовать правила маршрутизации для поддержки 404 и перенаправить их в конфигурацию хэша:

<RoutingRules>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website1/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website1#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website2/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website2#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
    <RoutingRule>
        <Condition>
            <KeyPrefixEquals>website3/</KeyPrefixEquals>
            <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
        </Condition>
        <Redirect>
            <Protocol>https</Protocol>
            <HostName>my.host.com</HostName>
            <ReplaceKeyPrefixWith>website3#</ReplaceKeyPrefixWith>
        </Redirect>
    </RoutingRule>
</RoutingRules>

В моем коде js мне нужно было обработать его с помощью baseNameconfig для реакции-маршрутизатора. Прежде всего, убедитесь, что ваши зависимости совместимы, я установил, с history==4.0.0которым был несовместим react-router==3.0.1.

Мои зависимости:

  • «история»: «3.2.0»,
  • «реагировать»: «15.4.1»,
  • «реаги-редукс»: «4.4.6»,
  • «реагирующий маршрутизатор»: «3.0.1»,
  • «response-router-redux»: «4.0.7»,

Я создал history.jsфайл для загрузки истории:

import {useRouterHistory} from 'react-router';
import createBrowserHistory from 'history/lib/createBrowserHistory';

export const browserHistory = useRouterHistory(createBrowserHistory)({
    basename: '/website1/',
});

browserHistory.listen((location) => {
    const path = (/#(.*)$/.exec(location.hash) || [])[1];
    if (path) {
        browserHistory.replace(path);
    }
});

export default browserHistory;

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

Теперь вы можете использовать этот файл для настройки вашего хранилища и вашего корневого файла.

import {routerMiddleware} from 'react-router-redux';
import {applyMiddleware, compose} from 'redux';

import rootSaga from '../sagas';
import rootReducer from '../reducers';

import {createInjectSagasStore, sagaMiddleware} from './redux-sagas-injector';

import {browserHistory} from '../history';

export default function configureStore(initialState) {
    const enhancers = [
        applyMiddleware(
            sagaMiddleware,
            routerMiddleware(browserHistory),
        )];

    return createInjectSagasStore(rootReducer, rootSaga, initialState, compose(...enhancers));
}
import React, {PropTypes} from 'react';
import {Provider} from 'react-redux';
import {Router} from 'react-router';
import {syncHistoryWithStore} from 'react-router-redux';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import variables from '!!sass-variable-loader!../../../css/variables/variables.prod.scss';
import routesFactory from '../routes';
import {browserHistory} from '../history';

const muiTheme = getMuiTheme({
    palette: {
        primary1Color: variables.baseColor,
    },
});

const Root = ({store}) => {
    const history = syncHistoryWithStore(browserHistory, store);
    const routes = routesFactory(store);

    return (
        <Provider {...{store}}>
            <MuiThemeProvider muiTheme={muiTheme}>
                <Router {...{history, routes}} />
            </MuiThemeProvider>
        </Provider>
    );
};

Root.propTypes = {
    store: PropTypes.shape({}).isRequired,
};

export default Root;

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


3

Теперь вы можете сделать это с помощью Lambda @ Edge, чтобы переписать пути

Вот рабочая лямбда-функция Edge:

  1. Создайте новую лямбда-функцию, но используйте одну из существующих ранее чертежей вместо пустой функции.
  2. Выполните поиск «cloudfront» и выберите cloudfront-response-generation из результатов поиска.
  3. После создания функции замените содержимое на приведенное ниже. Мне также пришлось изменить время выполнения узла на 10.x, потому что Cloudfront не поддерживал узел 12 на момент написания.
'use strict';
exports.handler = (event, context, callback) => {

    // Extract the request from the CloudFront event that is sent to Lambda@Edge 
    var request = event.Records[0].cf.request;

    // Extract the URI from the request
    var olduri = request.uri;

    // Match any '/' that occurs at the end of a URI. Replace it with a default index
    var newuri = olduri.replace(/\/$/, '\/index.html');

    // Log the URI as received by CloudFront and the new URI to be used to fetch from origin
    console.log("Old URI: " + olduri);
    console.log("New URI: " + newuri);

    // Replace the received URI with the URI that includes the index page
    request.uri = newuri;

    return callback(null, request);
};

В вашем поведении облачного фронта вы отредактируете его, добавив вызов этой лямбда-функции в «Запрос зрителя» введите описание изображения здесь

Полное руководство: https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/


1
В вашем примере кода пропущена только строка:return callback(null, request);
Pherrymason

2

Если вы попали сюда в поисках решения, которое работает с React Router и AWS Amplify Console - вы уже знаете, что не можете напрямую использовать правила перенаправления CloudFront, поскольку Amplify Console не предоставляет CloudFront Distribution для приложения.

Решение, однако, очень простое - вам просто нужно добавить правило перенаправления / перезаписи в Amplify Console следующим образом:

Правило перезаписи консоли для React Router

Смотрите следующие ссылки для получения дополнительной информации (и правила для копирования на скриншоте):


0

Я искал ответ на это сам. Похоже, что S3 поддерживает только перенаправления, вы не можете просто переписать URL-адрес и молча вернуть другой ресурс. Я рассматриваю возможность использования моего скрипта сборки, чтобы просто сделать копии моего index.html во всех необходимых местах пути. Может быть, это будет работать для вас тоже.


2
Генерация индексных файлов для каждого пути тоже приходила мне в голову, но было бы сложно иметь динамические пути, например example.com/groups/5/show . Если вы видите мой ответ на этот вопрос, я считаю, что это решает проблему по большей части. Это что-то вроде хака, но, по крайней мере, это работает.
Марк Наттер

Лучше развернуть за сервером nginx и вернуть index.html для всех входящих URL-адресов. Я сделал это успешно с развертыванием приложений Ember.
moha297

-3

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

экспорт const AppRoutingModule: ModuleWithProviders = RouterModule.forRoot (маршруты, {useHash: true, scrollPositionRestoration: 'enabled'});

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.