S3 Static Website Hosting Route All Paths to Index.html

250

Używam S3 do hostowania aplikacji javascript, która będzie używać pushStates HTML5. Problem polega na tym, że jeśli użytkownik doda zakładkę do dowolnego adresu URL, nie rozwiąże niczego. To, czego potrzebuję, to możliwość przyjmowania wszystkich żądań adresu URL i podawania root index.html w moim segmencie S3, zamiast tylko pełnego przekierowania. Wtedy moja aplikacja javascript mogłaby przeanalizować adres URL i wyświetlić odpowiednią stronę.

Czy jest jakiś sposób, aby powiedzieć S3, aby wyświetlał plik index.html dla wszystkich żądań URL zamiast przekierowywać? Byłoby to podobne do konfigurowania apache do obsługi wszystkich przychodzących żądań przez serwowanie pojedynczego pliku index.html, jak w tym przykładzie: https://stackoverflow.com/a/10647521/1762614 . Naprawdę chciałbym uniknąć uruchamiania serwera WWW tylko do obsługi tych tras. Robienie wszystkiego z S3 jest bardzo atrakcyjne.

Mark Nutter
źródło
Czy znalazłeś rozwiązanie tego problemu?
w2lame,

Odpowiedzi:

301

Bardzo łatwo go rozwiązać bez włamań do adresów URL, z pomocą CloudFront.

  • Utwórz segment S3, na przykład: zareaguj
  • Twórz dystrybucje CloudFront za pomocą tych ustawień:
    • Domyślny obiekt główny : index.html
    • Nazwa domeny pochodzenia : domena segmentu S3, na przykład: reag.s3.amazonaws.com
  • Przejdź na kartę Strony błędów , kliknij Utwórz niestandardową odpowiedź na błąd :
    • Kod błędu HTTP : 403: Zabroniony (404: Nie znaleziono, w przypadku witryny S3 Static)
    • Dostosuj odpowiedź na błąd : Tak
    • Ścieżka strony odpowiedzi : /index.html
    • Kod odpowiedzi HTTP : 200: OK
    • Kliknij Utwórz
Lenaten
źródło
8
Dzięki. Najlepsza jak dotąd odpowiedź.
jgb
a co nie jest tak oczywiste, zachowujesz lokalizację, aby móc wykonywać „naturalne” trasy.
Łukasz Marek Sielski
5
działało to dla mnie jak urok, tylko niestandardowy kod błędu, którego potrzebowałem, to 404, a nie 403
Jeremy S.
4
Trochę włamania, ale działa świetnie :) Byłoby miło, gdyby CloudFront po prostu pozwolił nam zmapować zakres ścieżek do pliku S3 (bez przekierowania).
Bob
3
To mi nie działa. To rozwiązanie zawsze przekierowuje na stronę główną, a nie na właściwe strony ...
Jim,
201

Sposób, w jaki udało mi się to uruchomić, jest następujący:

W sekcji Edytuj reguły przekierowania konsoli S3 dla swojej domeny dodaj następujące reguły:

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

Spowoduje to przekierowanie wszystkich ścieżek, w wyniku których 404 nie zostanie znalezione w domenie głównej za pomocą wersji mieszania ścieżki. Więc http://twojadomena.com.com/posts przekieruje na http://twojadomena.com.com/#!/posts pod warunkiem, że nie ma pliku w / posts.

Aby jednak użyć pushStates HTML5, musimy przyjąć to żądanie i ręcznie ustalić poprawne pushState na podstawie ścieżki hash-bang. Dodaj to na górze pliku index.html:

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

Pobiera to skrót i przekształca go w pushState HTML5. Od tego momentu możesz używać pushStates, aby mieć w aplikacji ścieżki nie-hash-bang.

Mark Nutter
źródło
4
To rozwiązanie działa świetnie! W rzeczywistości angularjs automatycznie wykona historię pushState, jeśli skonfigurowany jest tryb HTML.
wcandillon
1
Nie powiedzie się to ze starszą wersją IE, jeśli w adresach URL znajdują się parametry GET, prawda? Jak poradzić sobie z tym problemem?
clexmond
3
Dzięki! Działa to dobrze dla mnie z kręgosłupem z niewielką poprawką. Dodałem czek dla starszych przeglądarek: <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 Gray
10
Udało się react-routerz tym rozwiązaniem, używając HTMLState pushStates i<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
Felix D.
5
Nie działa w safari i stanowi duży problem ze strategią wdrażania. Pisanie małego pliku js do przekierowania jest rodzajem podejrzanego podejścia. Problemem jest także liczba przekierowań. Próbuję ustalić, czy istnieje sposób, aby wszystkie adresy URL S3 zawsze wskazywały na index.html.
moha297
129

Jest kilka problemów z podejściem opartym na S3 / Redirect wspomnianym przez innych.

  1. Przekierowania przekierowujące zdarzają się w miarę rozwiązywania ścieżek aplikacji. Na przykład: www.myapp.com/path/for/test zostaje przekierowany jako www.myapp.com/#/path/for/test
  2. Na pasku adresu pojawia się migotanie, gdy „#” przychodzi i odchodzi z powodu działania twojego środowiska SPA.
  3. Ma to wpływ na SEO, ponieważ: „Hej! Google go zmusza do przekierowania ”
  4. Obsługa Twojej aplikacji przez Safari jest bardzo prosta.

Rozwiązaniem jest:

  1. Upewnij się, że masz skonfigurowaną trasę indeksu dla swojej witryny. Przeważnie jest to index.html
  2. Usuń reguły routingu z konfiguracji S3
  3. Umieść Cloudfront przed wiadrem S3.
  4. Skonfiguruj reguły stron błędów dla instancji Cloudfront. W regułach błędów określ:

    • Kod błędu HTTP: 404 (i 403 lub inne błędy według potrzeb)
    • Błąd buforowania Minimalna wartość TTL (sekundy): 0
    • Dostosuj odpowiedź: Tak
    • Ścieżka strony odpowiedzi: /index.html
    • Kod odpowiedzi HTTP: 200

      1. Dla potrzeb SEO + upewnienia się, że index.html nie buforuje, wykonaj następujące czynności:
    • Skonfiguruj instancję EC2 i skonfiguruj serwer nginx.

    • Przypisz publiczny adres IP do instancji EC2.
    • Utwórz ELB, który ma instancję EC2 utworzoną jako instancja
    • Powinieneś być w stanie przypisać ELB do swojego DNS.
    • Teraz skonfiguruj serwer nginx, aby wykonywał następujące czynności: Proxy_pass wszystkie żądania do CDN (tylko dla index.html, obsługuj inne zasoby bezpośrednio z chmury) i dla botów wyszukiwania przekierowuj ruch zgodnie z usługami takimi jak Prerender.io

Mogę pomóc w bardziej szczegółowych szczegółach dotyczących konfiguracji nginx, po prostu zostaw notatkę. Nauczyłem się tego na własnej skórze.

Po zaktualizowaniu dystrybucji frontowej w chmurze. Unieważnij raz pamięć podręczną działającą w chmurze, aby być w nieskazitelnym trybie. Naciśnij adres URL w przeglądarce i wszystko powinno być dobre.

moha297
źródło
6
ponieważ S3 odpowiada komunikatem 403 Zabronione, gdy plik nie istnieje, myślę, że krok 4 powyżej musi zostać zduplikowany również dla kodu błędu HTTP 403
Andreas
4
Dla mnie jest to jedyna odpowiedź, która powoduje oczekiwane (zaakceptowane) zachowanie
mabe.berlin
1
@ moha297 w punkcie 5, czy zasadniczo konfigurujesz swoją witrynę do pobierania z nginx, które następnie proxy z CDN (z wyjątkiem index.html i żądań robota)? Jeśli tak jest, czy nie straciłbyś korzyści z serwerów brzegowych CDN?
Rahul Patel,
2
@ moha297 czy możesz wyjaśnić ten komentarz: „Nigdy nie powinieneś podawać index.html z CDN”? Nie widzę problemu z udostępnianiem index.html z S3 z CloudFront.
Carl G
1
Zobacz stackoverflow.com/a/10622078/4185989, aby uzyskać więcej informacji o tym, jak traktuje się TTL 0 (krótka wersja: jest buforowane przez Cloudfront, ale If-Modified-Sincewysyłane jest żądanie GET do źródła) - może być użytecznym rozwiązaniem dla osób, które nie chcą skonfigurować serwer jak w kroku 5.
jmq
18

Jest to styczne, ale oto wskazówka dla tych, którzy używają biblioteki React Router Rackta z historią przeglądarki (HTML5), którzy chcą hostować na S3.

Załóżmy, że użytkownik odwiedza /foo/bearstatyczną witrynę hostowaną przez S3. Biorąc pod uwagę wcześniejszą sugestię Davida , reguły przekierowania wyślą je na adres . Jeśli twoja aplikacja jest zbudowana przy użyciu historii przeglądarki, nie przyniesie to wiele dobrego. Jednak aplikacja jest ładowana w tym momencie i może teraz manipulować historią./#/foo/bear

Uwzględniając historię Rackta w naszym projekcie (zobacz także Korzystanie z historii niestandardowych z projektu React Router), możesz dodać detektora, który jest świadomy ścieżek historii skrótów i odpowiednio zastąpić ścieżkę, jak pokazano w tym przykładzie:

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'))
);

Przypomnę:

  1. Reguła przekierowania S3 Davida skieruje się /foo/beardo /#/foo/bear.
  2. Twoja aplikacja zostanie załadowana.
  3. Detektor historii wykryje #/foo/bearzapis historii.
  4. I zastąp historię historią właściwą ścieżką.

Linktagi będą działać zgodnie z oczekiwaniami, podobnie jak wszystkie inne funkcje historii przeglądarki. Jedynym minusem, jaki zauważyłem, jest przekierowanie śródmiąższowe, które występuje na pierwsze żądanie.

Inspiracją było rozwiązanie dla AngularJS i podejrzewam, że można je łatwo dostosować do dowolnego zastosowania.

Michael Ahlers
źródło
2
To pomogło mi Michael, dzięki! Możesz zmienić swoje odniesienie z historii i po prostu użyć BrowserHistory. tj.browserHistory.listen
Marshall Moutenot
Nie ma za co! Miło, że mogłem pomóc. Uzgodniono również, że w tym konkretnym przypadku użycia zaktualizowałem fragment kodu, aby rozwiązać ostrzeżenie o wycofaniu z React Router.
Michael Ahlers
Po wydaniu React-Router v3.0.0 to nie działa, ponieważ React-Router v3.0.0 korzysta z historii v3.0.0
Varand Pezeshkian
Każdy pomysł, jak zapobiec history.listen nieskończonej pętli połączeń? Spowodowane jest to zastąpieniem ścieżki.
Mirko Flyktman
14

Widzę 4 rozwiązania tego problemu. Pierwsze 3 zostały już uwzględnione w odpowiedziach, a ostatni jest moim wkładem.

  1. Ustaw dokument błędu na index.html.
    Problem : treść odpowiedzi będzie poprawna, ale kod stanu to 404, co boli SEO.

  2. Ustaw reguły przekierowania.
    Problem : adres URL jest zanieczyszczony, #!a strona ładuje się po załadowaniu.

  3. Skonfiguruj CloudFront.
    Problem : wszystkie strony zwrócą 404 od początku, więc musisz wybrać, jeśli nie będziesz niczego buforować (sugerowane TTL 0) lub jeśli będziesz buforować i będziesz mieć problemy z aktualizacją strony.

  4. Wstępnie wyrenderuj wszystkie strony.
    Problem : dodatkowa praca w celu wstępnego renderowania stron, szczególnie gdy strony często się zmieniają. Na przykład witryna z wiadomościami.

Moją propozycją jest skorzystanie z opcji 4. Jeśli wstępnie wyrenderujesz wszystkie strony, nie będzie 404 błędów dla oczekiwanych stron. Strona ładuje się dobrze, a środowisko przejmuje kontrolę i działa normalnie jako SPA. Możesz także ustawić dokument błędu, aby wyświetlał ogólną stronę error.html oraz regułę przekierowania, aby przekierowywać błędy 404 na stronę 404.html (bez hashbanga).

Jeśli chodzi o 403 zabronione błędy, w ogóle ich nie dopuszczam. W mojej aplikacji uważam, że wszystkie pliki w segmencie hosta są publiczne i ustawiam to za pomocą opcji Wszyscy z uprawnieniem do odczytu . Jeśli Twoja witryna ma prywatne strony, pozwolenie użytkownikowi na zobaczenie układu HTML nie powinno stanowić problemu. To, czego potrzebujesz do ochrony, to dane, a odbywa się to w wewnętrznej bazie danych.

Ponadto, jeśli masz prywatne zasoby, takie jak zdjęcia użytkowników, możesz zapisać je w innym segmencie. Ponieważ zasoby prywatne wymagają takiej samej opieki jak dane i nie można ich porównywać z plikami zasobów używanymi do hostowania aplikacji.

Zanon
źródło
1
a Twoja witryna ma świetny przykład użycia do wstępnego renderowania dla wszystkich stron. zanon.io/posts/… .- Dziękuję
frekele
Czy to czwarte podejście odnosi się do przeładowania adresu URL pushState przez użytkownika? Poradzi sobie z nawigacją, ale po przeładowaniu nadal będzie docierać do serwera.
Alpha
@Alpha, nie jestem pewien, czy poprawnie zrozumiałem twoje pytanie, ale po przeładowaniu byłoby to nowe żądanie. S3 otrzyma żądanie i ponownie zwróci wstępnie przygotowaną stronę. W tym przypadku nie ma serwera.
Zanon
@Zanon Ah, myślę, że rozumiem. Pomyślałem, że miało to na celu buforowanie wstępnie wstępnie wydrukowanych stron i unikanie sięgania po nieistniejące zasoby S3. Pominąłoby to trasy, które mają elementy dynamiczne, prawda?
Alpha
1
@Zanon W końcu rozumiem - dzięki! Tak właśnie miałem na myśli. :)
Alpha
13

Zetknąłem się dzisiaj z tym samym problemem, ale rozwiązanie @ Mark-Nutter było niekompletne, aby usunąć hashbang z mojej aplikacji angularjs.

W rzeczywistości musisz przejść do Edycji uprawnień , kliknąć Dodaj więcej uprawnień, a następnie dodać odpowiednią listę w wiadrze do wszystkich. Przy tej konfiguracji AWS S3 będzie mógł teraz zwrócić błąd 404, a następnie reguła przekierowania odpowiednio złapie sprawę.

Takie jak to : wprowadź opis zdjęcia tutaj

Następnie możesz przejść do Edycji reguł przekierowania i dodać tę regułę:

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

Tutaj możesz zastąpić nazwę hosta subdomain.domain.fr swoją domeną i KeyPrefix #! / Jeśli nie używasz metody hashbang do celów SEO.

Oczywiście wszystko to zadziała tylko wtedy, gdy masz już konfigurację trybu html5 w aplikacji kątowej.

$locationProvider.html5Mode(true).hashPrefix('!');
davidbonachera
źródło
moim jedynym problemem jest to, że masz błysk hashbangu, którego nie masz z czymś takim jak reguła nginx. Użytkownik jest na stronie i odświeża: / products / 1 -> #! / Products / 1 -> / products / 1
Intellix 29.09.2015
1
Myślę, że powinieneś dodać regułę dla błędu 403 zamiast przyznawać uprawnienia do listy wszystkim.
Hamish Moffatt,
11

Najłatwiejszym rozwiązaniem, aby aplikacja Angular 2+ była obsługiwana z Amazon S3 i bezpośrednich adresów URL, jest określenie index.html zarówno jako dokumentów indeksu, jak i błędów w konfiguracji segmentu S3.

wprowadź opis zdjęcia tutaj

Siergiej Kandaurow
źródło
11
To jest ta sama odpowiedź na tę mocno odrzuconą odpowiedź . Działa dobrze, ale tylko dla bodyodpowiedzi. Kod stanu to 404 i zaszkodzi SEO.
Zanon
Ponieważ działa to tylko w bodyprzypadku, gdy masz w nim zaimportowane skrypty, headnie będą one działać, gdy bezpośrednio trafisz na którąkolwiek z tras podrzędnych na swojej stronie
Mohamed Hajr
4

ponieważ problem nadal istnieje, pomyślałem, że wprowadzę inne rozwiązanie. Mój przypadek polegał na tym, że chciałem automatycznie wdrożyć wszystkie żądania ściągnięcia do s3 w celu przetestowania przed scaleniem, aby były dostępne na [mojadomena] / pull-request / [pr number] /
(np. Www.example.com/pull-requests/822/ )

Zgodnie z moją najlepszą wiedzą, scenariusze inne niż reguły s3 pozwoliłyby na posiadanie wielu projektów w jednym segmencie przy użyciu routingu HTML5, więc chociaż powyższa sugestia nad większością głosów działa dla projektu w folderze głównym, nie dotyczy wielu projektów we własnych podfolderach.

Wskazałem więc moją domenę na mój serwer, na którym wykonałem zadanie po konfiguracji 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;
}

próbuje pobrać plik, a jeśli nie zostanie znaleziony, zakłada, że ​​jest to trasa HTML5 i próbuje tego. Jeśli masz stronę kątową 404 dla nieodnalezionych tras, nigdy nie dostaniesz się do @not_found i otrzymasz zwrotną stronę 404 zamiast nieodnalezionych plików, co można naprawić za pomocą niektórych, jeśli reguła w @get_routes lub coś takiego.

Muszę powiedzieć, że nie czuję się zbyt komfortowo w zakresie konfiguracji nginx i używania wyrażeń regularnych w tej kwestii, dostałem to z pewną próbą i błędem, więc chociaż działa, jestem pewien, że jest miejsce na ulepszenia i proszę podziel się swoimi przemyśleniami .

Uwaga : usuń reguły przekierowania s3, jeśli masz je w konfiguracji S3.

a btw działa w Safari

Andrew Arnautov
źródło
cześć .. dzięki za rozwiązanie ... gdzie umieścisz ten plik conf nginx dla wdrożenia s3. czy jest to to samo co elastyczna łodyga fasoli, w której muszę utworzyć folder .exextensions i umieścić go w pliku proxy.config?
user3124360
@ user3124360 Nie jestem pewien co do elastycznego beanstacka, ale w moim przypadku wskazuję nazwę domeny na instancję ec2 i mam tam konfigurację nginx. Więc żądanie idzie KLIENT -> DNS -> EC2 -> S3 -> KLIENT.
Andrew Arnautov
tak, robię coś bardzo podobnego ... z konfiguracją nginx tutaj github.com/davezuko/react-redux-starter-kit/issues/1099 ... dzięki za opublikowanie pliku conf .. widzę, jak rozwinąć ten EC2 -> Połączenie S3 teraz
użytkownik3124360
3

Szukał tego samego rodzaju problemu. Skończyło się na użyciu kombinacji sugerowanych rozwiązań opisanych powyżej.

Po pierwsze, mam wiadro s3 z wieloma folderami, każdy folder reprezentuje stronę reagującą / reduxową. Używam również Cloudfront do unieważnienia pamięci podręcznej.

Musiałem więc użyć reguł routingu do obsługi 404 i przekierować je do konfiguracji skrótu:

<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>

W moim kodzie js musiałem obsługiwać go za pomocą baseNamekonfiguracji routera reagującego. Przede wszystkim upewnij się, że twoje zależności są interoperacyjne, mam zainstalowane, z którymi history==4.0.0był niezgodny react-router==3.0.1.

Moje zależności to:

  • „historia”: „3.2.0”,
  • „reagować”: „15.4.1”,
  • „React-redux”: „4.4.6”,
  • „Reaguj router”: „3.0.1”,
  • „React-router-redux”: „4.0.7”,

Utworzyłem history.jsplik do ładowania historii:

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;

Ten fragment kodu pozwala obsłużyć 404 wysłany przez serwer z mieszaniem i zastąpić je w historii ładowaniem naszych tras.

Możesz teraz użyć tego pliku do skonfigurowania sklepu i pliku głównego.

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;

Mam nadzieję, że to pomoże. Zauważysz, że w tej konfiguracji używam wtryskiwacza redux i wtryskiwacza homebrew sagas do asynchronicznego ładowania javascript przez routing. Nie przejmuj się tymi liniami.

Guillaume Cisco
źródło
3

Możesz teraz to zrobić za pomocą Lambda @ Edge, aby przepisać ścieżki

Oto działająca funkcja lambda @ Edge:

  1. Utwórz nową funkcję Lambda, ale zamiast jednej pustej funkcji użyj jednego z wcześniej istniejących schematów.
  2. Wyszukaj „cloudfront” i wybierz generowanie odpowiedzi cloudfront z wyników wyszukiwania.
  3. Po utworzeniu funkcji zamień zawartość na niższą. Musiałem także zmienić środowisko uruchomieniowe węzła na 10.x, ponieważ program Cloudfront nie obsługiwał węzła 12 w momencie pisania.
'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);
};

W swoich zachowaniach w chmurze zmodyfikujesz je, aby dodać wywołanie do tej funkcji lambda w „Żądaniu przeglądarki” wprowadź opis zdjęcia tutaj

Pełny samouczek: https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/

Loren
źródło
1
W twoim kodzie brakuje tylko linii:return callback(null, request);
Pherrymason
2

Jeśli wylądowałeś tutaj, szukając rozwiązania współpracującego z React Router i konsolą AWS Amplify - już wiesz, że nie możesz bezpośrednio korzystać z reguł przekierowania CloudFront, ponieważ Amplify Console nie ujawnia dystrybucji CloudFront dla aplikacji.

Rozwiązanie jest jednak bardzo proste - wystarczy dodać regułę przekierowywania / przepisywania w konsoli Amplify w następujący sposób:

Wzmocnij regułę przepisywania konsoli dla React Router

Zobacz poniższe linki, aby uzyskać więcej informacji (i regułę przyjazną dla kopiowania ze zrzutu ekranu):

Yaro
źródło
0

Sam szukałem odpowiedzi na to pytanie. S3 wydaje się obsługiwać tylko przekierowania, nie można po prostu przepisać adresu URL i po cichu zwrócić inny zasób. Zastanawiam się nad użyciem skryptu kompilacji do wykonania kopii mojego pliku index.html we wszystkich wymaganych lokalizacjach ścieżek. Może to też zadziała dla ciebie.

Ed Thomas
źródło
2
Generowanie plików indeksu dla każdej ścieżki również przyszło mi do głowy, ale dynamiczne ścieżki takie jak example.com/groups/5/show byłyby trudne . Jeśli zobaczysz moją odpowiedź na to pytanie, uważam, że to w większości rozwiązuje problem. To trochę hack, ale przynajmniej działa.
Mark Nutter
Lepiej wdrożyć za serwerem Nginx i zwrócić index.html dla wszystkich przychodzących adresów URL. Udało mi się to z wdrożeniem aplikacji ember w heroku.
moha297
-3

Żeby ująć niezwykle prostą odpowiedź. Wystarczy użyć strategii lokalizacji skrótu dla routera, jeśli hostujesz na S3.

export const AppRoutingModule: ModuleWithProviders = RouterModule.forRoot (trasy, {useHash: true, scrollPositionRestoration: 'enabled'});

Meester Over
źródło