S3 Static Website Hosting Route Все пути к Index.html

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

Есть ли способ сказать S3 для обслуживания index.html для всех запросов URL вместо того, чтобы делать перенаправления? Это было бы похоже на настройку apache для обработки всех входящих запросов, обслуживая один index.html, как в этом примере: qaru.site/info/37054/.... Мне бы очень хотелось избежать использования веб-сервера только для обработки этих маршрутов. Выполнение всего, начиная с S3, очень привлекательно.

Ответ 1

Решение Mark не плохо, но есть еще более простое решение. В свойствах вашего ведра в Документе ошибки просто используйте тот же файл, что и Индексный документ. Рамочные структуры JavaScript, такие как Backbone, AngularJS и т.д., Будут работать из коробки таким образом, и обновление страницы будет полностью поддерживаться.

Ответ 2

Это очень легко решить без хакеров, с помощью CloudFront.

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

Ответ 3

Как я мог заставить это работать:

В разделе Изменить правила переадресации консоли 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.

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

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

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

Ответ 4

Есть несколько проблем с подходом на основе 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 в браузере, и все должно быть хорошо.

Ответ 5

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

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

В том числе Rackt history в нашем проекте (см. также Используя пользовательские истории из проекта 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'))
);

Повторить:

  • Правило перенаправления David S3 направит /foo/bear на /#/foo/bear.
  • Ваше приложение будет загружено.
  • Слушатель истории обнаруживает нотацию #/foo/bear.
  • И замените историю правильным путем.

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

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

Ответ 6

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

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

  • Установите правила перенаправления.
    Проблема: URL-адрес, загрязненный с помощью #!, и страница мигает при загрузке.

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

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

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

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

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

Ответ 7

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

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

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

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

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

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

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

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

Ответ 8

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

enter image description here

Ответ 9

поскольку проблема все еще существует, хотя я бросаю другое решение. Мое дело было в том, что я хотел автоматически развернуть все запросы на pull для s3 для тестирования до слияния, чтобы сделать их доступными на [mydomain]/pull-requests/[pr number]/
(например, 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 route и пытается это сделать. Если у вас есть страница 404 angular для не найденных маршрутов, вы никогда не получите @not_found и не получите angular 404 страницу вместо найденных файлов, которые могут быть исправлены с помощью некоторого правила if в @get_routes или что-то в этом роде.

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

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

и btw работает в Safari

Ответ 10

Ищет ту же проблему. Я закончил использовать сочетание предлагаемых решений, описанных выше.

Во-первых, у меня есть ведро 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-коде мне нужно было обработать его с помощью baseName config для response-router. Прежде всего, убедитесь, что ваши зависимости совместимы, я установил history==4.0.0, который был несовместим с react-router==3.0.1.

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

  • "history": "3.2.0",
  • "реагировать": "15.4.1",
  • "react-redux": "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 асинхронно через маршрутизацию. Не обращайте внимания на тезисы.

Ответ 11

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

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

Amplify Console Rewrite rule for React Router

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

Ответ 12

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

Ответ 13

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

{ path: '**', redirectTo: '' }

Затем, как упоминалось в бесчисленных сообщениях выше, убедитесь, что вы перенаправляете ошибки 404/403 в index.html с 200 статусом. Проблема в том, что это приводит к обновлению браузера, загружая базовый href как (href + предыдущий маршрут). Если вы просматривали представление маршрутизатора на

www.my-app.com/home, то обновление отобразит

www.my-app.com/home/home

Чтобы удалить дублированный маршрут маршрута, используйте модуль APP_BASE_HREF, чтобы переназначить базовую базу браузера href так же, как это

Если вам нужно сохранить первый параметр url, добавьте несколько результатов из раскола '/'.

Браузер попадает в ваш редирект SPA для www.your-app.com/home/home теперь заменяет URL-адрес www.your-app.com/home, и приложение будет вести себя так, как ожидалось, от вашей конфигурации маршрутизации в приложении

Ответ 14

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

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