S3 Static Website Hosting Route Alle Pfade zu Index.html

250

Ich verwende S3, um eine Javascript-App zu hosten, die HTML5-PushStates verwendet. Das Problem ist, wenn der Benutzer eine der URLs mit einem Lesezeichen versehen kann, wird keine Lösung gefunden. Was ich brauche, ist die Fähigkeit, alle URL-Anfragen entgegenzunehmen und die root index.html in meinem S3-Bucket bereitzustellen, anstatt nur eine vollständige Umleitung durchzuführen. Dann könnte meine Javascript-Anwendung die URL analysieren und die richtige Seite bereitstellen.

Gibt es eine Möglichkeit, S3 anzuweisen, die index.html für alle URL-Anforderungen bereitzustellen, anstatt Weiterleitungen durchzuführen? Dies ähnelt dem Einrichten von Apache zur Verarbeitung aller eingehenden Anforderungen durch Bereitstellen einer einzelnen index.html wie in diesem Beispiel: https://stackoverflow.com/a/10647521/1762614 . Ich möchte wirklich vermeiden, einen Webserver zu betreiben, nur um diese Routen zu handhaben. Alles von S3 aus zu tun ist sehr ansprechend.

Mark Nutter
quelle
Haben Sie eine Lösung dafür gefunden?
w2lame

Antworten:

301

Mit Hilfe von CloudFront ist es sehr einfach, es ohne URL-Hacks zu lösen.

  • Erstellen Sie einen S3-Bucket, zum Beispiel: reagieren
  • Erstellen Sie CloudFront-Distributionen mit folgenden Einstellungen:
    • Standardstammobjekt : index.html
    • Name der Ursprungsdomäne : S3-Bucket-Domäne, zum Beispiel: react.s3.amazonaws.com
  • Gehen Sie zur Registerkarte Fehlerseiten und klicken Sie auf Benutzerdefinierte Fehlerantwort erstellen :
    • HTTP-Fehlercode : 403: Verboten (404: Nicht gefunden, bei S3 Static Website)
    • Fehlerantwort anpassen : Ja
    • Antwortseitenpfad : /index.html
    • HTTP-Antwortcode : 200: OK
    • Klicken Sie auf Erstellen
lenaten
quelle
8
Vielen Dank. Die bisher beste Antwort.
JGB
und was nicht so offensichtlich ist, behalten Sie den Standort bei, damit Sie "natürliches" Routing durchführen können.
Lukasz Marek Sielski
5
Dies funktionierte wie ein Zauber für mich, nur der benutzerdefinierte Fehlercode, den ich brauchte, war 404, nicht 403
Jeremy S.
4
Ein bisschen hacken, aber funktioniert super :) Es wäre schön, wenn CloudFront uns einfach eine Reihe von Pfaden einer S3-Datei zuordnen lassen würde (ohne Umleitung).
Bob
3
Das funktioniert bei mir nicht. Diese Lösung leitet immer zur Startseite und nicht zu den richtigen Seiten weiter ...
Jim
201

Ich konnte dies wie folgt zum Laufen bringen:

Im bearbeiten Umleitungsregeln Abschnitt der S3 - Konsole für Ihre Domain, fügen Sie die folgenden Regeln:

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

Dadurch werden alle Pfade, die dazu führen, dass ein 404 nicht gefunden wird, mit einer Hash-Bang-Version des Pfads in Ihre Stammdomäne umgeleitet. Daher wird http://yourdomainname.com/posts zu http://yourdomainname.com/#!/posts umgeleitet, sofern keine Datei unter / posts vorhanden ist.

Um HTML5 pushStates zu verwenden, müssen wir diese Anforderung annehmen und manuell den richtigen pushState basierend auf dem Hash-Bang-Pfad einrichten. Fügen Sie dies also oben in Ihre index.html-Datei ein:

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

Dadurch wird der Hash erfasst und in einen HTML5-PushState umgewandelt. Ab diesem Zeitpunkt können Sie pushStates verwenden, um Nicht-Hash-Bang-Pfade in Ihrer App zu haben.

Mark Nutter
quelle
4
Diese Lösung funktioniert super! In der Tat führt anglejs automatisch den Verlauf pushState aus, wenn der HTML-Modus konfiguriert ist.
Wcandillon
1
Dies wird mit einer älteren Version des IE fehlschlagen, wenn Ihre URLs GET-Parameter enthalten. Richtig? Wie kommen Sie um dieses Problem herum?
Clexmond
3
Vielen Dank! Dies funktionierte gut für mich am Backbone mit einem kleinen Tweak. Ich habe in einem Check für ältere Browser hinzugefügt: <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
Gelang mit react-routermit dieser Lösung unter Verwendung von HTML5 pushStates und<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
Felix D.
5
Es funktioniert nicht auf Safari und ist ein großes Problem mit der Bereitstellungsstrategie. Das Schreiben eines kleinen js zum Umleiten ist eine Art schäbiger Ansatz. Auch die Anzahl der Weiterleitungen ist ein Problem. Ich versuche herauszufinden, ob es eine Möglichkeit gibt, dass alle S3-URLs immer auf index.html verweisen.
Moha297
129

Es gibt nur wenige Probleme mit dem von anderen erwähnten S3 / Redirect-basierten Ansatz.

  1. Mehrere Weiterleitungen erfolgen, wenn die Pfade Ihrer App aufgelöst werden. Beispiel: www.myapp.com/path/for/test wird als www.myapp.com/#/path/for/test umgeleitet
  2. In der URL-Leiste flackert es, wenn das '#' aufgrund der Aktion Ihres SPA-Frameworks kommt und geht.
  3. Das SEO ist betroffen, weil - 'Hey! Sein Google zwingt seine Hand auf Weiterleitungen '
  4. Die Safari-Unterstützung für Ihre App ist ein Kinderspiel.

Die Lösung ist:

  1. Stellen Sie sicher, dass Sie die Indexroute für Ihre Website konfiguriert haben. Meistens ist es index.html
  2. Entfernen Sie Routing-Regeln aus S3-Konfigurationen
  3. Stellen Sie eine Cloudfront vor Ihren S3-Bucket.
  4. Konfigurieren Sie Fehlerseitenregeln für Ihre Cloudfront-Instanz. Geben Sie in den Fehlerregeln Folgendes an:

    • HTTP-Fehlercode: 404 (und 403 oder andere Fehler nach Bedarf)
    • Fehler-Caching Minimale TTL (Sekunden): 0
    • Antwort anpassen: Ja
    • Antwortseitenpfad: /index.html
    • HTTP-Antwortcode: 200

      1. Gehen Sie wie folgt vor, um sicherzustellen, dass Ihre index.html nicht zwischengespeichert wird:
    • Konfigurieren Sie eine EC2-Instanz und richten Sie einen Nginx-Server ein.

    • Weisen Sie Ihrer EC2-Instanz eine öffentliche IP zu.
    • Erstellen Sie eine ELB mit der EC2-Instanz, die Sie als Instanz erstellt haben
    • Sie sollten in der Lage sein, die ELB Ihrem DNS zuzuweisen.
    • Konfigurieren Sie jetzt Ihren Nginx-Server so, dass er die folgenden Schritte ausführt: Proxy_pass alle Anforderungen an Ihr CDN (nur für index.html, andere Assets direkt von Ihrer Cloudfront aus bedienen) und für Such-Bots den Datenverkehr umleiten, wie von Diensten wie Prerender.io festgelegt

Ich kann Ihnen bei weiteren Details zum Nginx-Setup helfen. Hinterlassen Sie einfach eine Notiz. Habe es auf die harte Tour gelernt.

Sobald die Cloud-Front-Distribution aktualisiert wurde. Machen Sie Ihren Cloudfront-Cache einmal ungültig, um sich im makellosen Modus zu befinden. Klicken Sie auf die URL im Browser und alles sollte gut sein.

moha297
quelle
6
Da S3 mit 403 Forbidden antwortet, wenn keine Datei vorhanden ist, muss Schritt 4 oben auch für den HTTP-Fehlercode 403 dupliziert werden
Andreas
4
Für mich ist dies die einzige Antwort, die zu einem erwarteten (akzeptierten) Verhalten führt
mabe.berlin
1
@ moha297 in Punkt 5 konfigurieren Sie Ihre Site grundsätzlich so, dass sie von nginx abgerufen wird, das dann Proxys vom CDN abgibt (mit Ausnahme von index.html- und Crawler-Anforderungen)? Wenn dies der Fall ist, würden Sie dann nicht den Vorteil von CDN-Edgeservern verlieren?
Rahul Patel
2
@ moha297 können Sie bitte diesen Kommentar erklären: "Sie sollten niemals index.html von einem CDN aus bereitstellen"? Ich sehe kein Problem beim Bereitstellen von index.html aus S3 mit CloudFront.
Carl G
1
Unter stackoverflow.com/a/10622078/4185989 finden Sie weitere Informationen dazu, wie eine TTL von 0 behandelt wird (Kurzversion: Sie wird von Cloudfront zwischengespeichert, aber eine If-Modified-SinceGET-Anforderung wird an den Ursprung gesendet) um einen Server wie in Schritt 5
einzurichten
18

Es ist tangential, aber hier ist ein Tipp für diejenigen, die Rackt's React Router-Bibliothek mit (HTML5) Browserverlauf verwenden und auf S3 hosten möchten.

Angenommen, ein Benutzer besucht /foo/bearIhre von S3 gehostete statische Website. Aufgrund des früheren Vorschlags Davids werden sie von Umleitungsregeln an gesendet /#/foo/bear. Wenn Ihre Anwendung mithilfe des Browserverlaufs erstellt wurde, hilft dies nicht viel. Ihre Anwendung ist jedoch zu diesem Zeitpunkt geladen und kann nun den Verlauf bearbeiten.

Wenn Sie den Rackt- Verlauf in unser Projekt aufnehmen (siehe auch Verwenden von benutzerdefinierten Verlaufsdaten aus dem React Router-Projekt), können Sie einen Listener hinzufügen, der die Hash-Verlaufspfade kennt, und den Pfad entsprechend ersetzen, wie in diesem Beispiel dargestellt:

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

Um es noch einmal zusammenzufassen:

  1. Davids S3-Umleitungsregel wird /foo/bearan weitergeleitet /#/foo/bear.
  2. Ihre Anwendung wird geladen.
  3. Der Verlaufslistener erkennt die #/foo/bearVerlaufsnotation.
  4. Und ersetzen Sie den Verlauf durch den richtigen Pfad.

LinkTags funktionieren wie erwartet, ebenso wie alle anderen Browserverlaufsfunktionen. Der einzige Nachteil, den ich bemerkt habe, ist die interstitielle Umleitung, die bei der ersten Anforderung erfolgt.

Dies wurde von einer Lösung für AngularJS inspiriert , und ich vermute, dass sie leicht an jede Anwendung angepasst werden kann.

Michael Ahlers
quelle
2
Das hat mir geholfen Michael, Danke! Möglicherweise möchten Sie Ihre Referenz aus dem Verlauf ändern und einfach BrowserHistory verwenden. dhbrowserHistory.listen
Marshall Moutenot
Bitte! Froh, dass ich Helfen kann. Auch vereinbart, und für diesen speziellen Anwendungsfall habe ich das Snippet aktualisiert, um eine Verfallswarnung von React Router zu lösen.
Michael Ahlers
Mit der Veröffentlichung von React-Router v3.0.0 funktioniert dies nicht, da React-Router v3.0.0 History v3.0.0
Varand Pezeshkian
Irgendeine Idee, wie man die Endlosschleife von history.listen verhindert? Verursacht durch Ersetzen des Pfades, denke ich.
Mirko Flyktman
14

Ich sehe 4 Lösungen für dieses Problem. Die ersten 3 wurden bereits in Antworten behandelt und die letzte ist mein Beitrag.

  1. Setzen Sie das Fehlerdokument auf index.html.
    Problem : Der Antworttext ist korrekt, aber der Statuscode lautet 404, was der SEO schadet.

  2. Legen Sie die Umleitungsregeln fest.
    Problem : URL verschmutzt mit #!und Seite blinkt beim Laden.

  3. Konfigurieren Sie CloudFront.
    Problem : Alle Seiten geben 404 vom Ursprung zurück. Sie müssen also auswählen, ob Sie nichts zwischenspeichern möchten (TTL 0 wie vorgeschlagen) oder ob Sie beim Aktualisieren der Site zwischenspeichern und Probleme haben.

  4. Alle Seiten vorrendern.
    Problem : Zusätzliche Arbeit zum Vorrendern von Seiten, insbesondere wenn sich die Seiten häufig ändern. Zum Beispiel eine Nachrichten-Website.

Mein Vorschlag ist, Option 4 zu verwenden. Wenn Sie alle Seiten vorrendern, treten für die erwarteten Seiten keine 404-Fehler auf. Die Seite wird gut geladen und das Framework übernimmt die Kontrolle und fungiert normal als SPA. Sie können das Fehlerdokument auch so einstellen, dass eine generische error.html-Seite und eine Umleitungsregel zum Umleiten von 404-Fehlern auf eine 404.html-Seite (ohne Hashbang) angezeigt werden.

In Bezug auf 403 Verbotene Fehler lasse ich sie überhaupt nicht zu. In meiner Anwendung, denke ich , dass alle Dateien innerhalb der Host - Eimer sind öffentlich und ich setze diese mit dem jeder Option mit der Leseberechtigung. Wenn Ihre Site über private Seiten verfügt, sollte es kein Problem sein , dem Benutzer das HTML- Layout anzuzeigen. Was Sie schützen müssen, sind die Daten, und dies erfolgt im Backend.

Wenn Sie über private Assets wie Benutzerfotos verfügen, können Sie diese in einem anderen Bucket speichern . Weil private Assets die gleiche Sorgfalt wie Daten benötigen und nicht mit den Asset-Dateien verglichen werden können, die zum Hosten der App verwendet werden.

Zanon
quelle
1
und Ihre Site hat ein großartiges Beispiel für die Verwendung zum Vorrendern für alle Seiten. zanon.io/posts/… .- Danke
frekele
Befasst sich dieser vierte Ansatz mit dem Benutzer, der die pushState-URL neu lädt? Die Navigation funktioniert einwandfrei, aber beim Neuladen erreicht es immer noch den Server.
Alpha
@Alpha, ich bin mir nicht sicher, ob ich Ihre Frage richtig verstanden habe, aber beim Neuladen würde sie als neue Anfrage fungieren. S3 würde die Anfrage empfangen und die vorgerenderte Seite erneut zurückgeben. In diesem Fall gibt es keinen Server.
Zanon
@ Zanon Ah, ich glaube ich verstehe. Ich dachte, es sollte vorgerenderte Seiten zwischenspeichern und vermeiden, dass nicht vorhandene S3-Ressourcen verwendet werden. Dies würde Routen mit dynamischen Elementen auslassen, oder?
Alpha
1
@ Zanon Ich verstehe endlich - danke! Ja das meinte ich. :)
Alpha
13

Ich bin heute auf dasselbe Problem gestoßen, aber die Lösung von @ Mark-Nutter war unvollständig, um den Hashbang aus meiner AngularJS-Anwendung zu entfernen.

Tatsächlich müssen Sie zu Berechtigungen bearbeiten gehen , auf Weitere Berechtigungen hinzufügen klicken und dann allen die richtige Liste in Ihrem Bucket hinzufügen . Mit dieser Konfiguration kann AWS S3 nun 404-Fehler zurückgeben, und die Umleitungsregel erkennt den Fall ordnungsgemäß.

Genau wie dieser : Geben Sie hier die Bildbeschreibung ein

Anschließend können Sie unter Umleitungsregeln bearbeiten die folgende Regel hinzufügen:

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

Hier können Sie den Hostnamen subdomain.domain.fr durch Ihre Domain und das KeyPrefix #! / Ersetzen, wenn Sie die Hashbang-Methode nicht für SEO-Zwecke verwenden.

All dies funktioniert natürlich nur, wenn Sie html5mode bereits in Ihrer Winkelanwendung eingerichtet haben.

$locationProvider.html5Mode(true).hashPrefix('!');
Davidbonachera
quelle
Mein einziges Problem dabei ist, dass Sie einen Hashbang-Blitz haben, den Sie mit so etwas wie einer Nginx-Regel nicht haben. Benutzer ist auf einer Seite und aktualisiert: / products / 1 -> #! / Products / 1 -> / products / 1
Intellix
1
Ich denke, Sie sollten eine Regel für einen 403-Fehler hinzufügen, anstatt allen Listenberechtigungen zu erteilen.
Hamish Moffatt
11

Die einfachste Lösung, um Angular 2+ -Anwendungen, die von Amazon S3 und direkten URLs bereitgestellt werden, funktionsfähig zu machen, besteht darin, index.html sowohl als Index- als auch als Fehlerdokumente in der S3-Bucket-Konfiguration anzugeben.

Geben Sie hier die Bildbeschreibung ein

Sergey Kandaurov
quelle
11
Dies ist die gleiche Antwort auf diese stark herabgestimmte Antwort . Es funktioniert gut, aber nur für bodydie Antwort. Der Statuscode wird 404 sein und es wird SEO schaden.
Zanon
Da dies nur funktioniert, bodywenn Sie Skripte haben, die Sie in die importieren, headfunktionieren diese nicht, wenn Sie direkt auf eine der
Unterrouten
4

da das problem immer noch da ist, werfe ich aber eine andere lösung ein. Mein Fall war, dass ich alle Pull-Anforderungen zum Testen automatisch auf s3 bereitstellen wollte, bevor sie zusammengeführt wurden, um sie unter [mydomain] / pull-request / [pr number] /
(z. B. www.example.com/pull-requests/822/) zugänglich zu machen . )

Nach meinem besten Wissen würden Szenarien ohne s3-Regeln es ermöglichen, mehrere Projekte mithilfe von HTML5-Routing in einem Bucket zu haben. Während der oben genannte Vorschlag für ein Projekt im Stammordner funktioniert, gilt dies nicht für mehrere Projekte in eigenen Unterordnern.

Also habe ich meine Domain auf meinen Server verwiesen, auf dem die folgende nginx-Konfiguration den Job erledigt hat

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

Es versucht, die Datei abzurufen, und wenn es nicht gefunden wird, geht es davon aus, dass es sich um eine HTML5-Route handelt, und versucht dies. Wenn Sie eine 404-Winkelseite für nicht gefundene Routen haben, gelangen Sie nie zu @not_found und erhalten eine eckige 404-Seite zurück, anstatt nicht gefundene Dateien, die mit einigen if-Regeln in @get_routes oder so behoben werden könnten.

Ich muss sagen, dass ich mich im Bereich der Nginx-Konfiguration und der Verwendung von Regex nicht besonders wohl fühle. Ich habe dies mit einigem Ausprobieren zum Laufen gebracht. Während dies funktioniert, bin ich sicher, dass es Raum für Verbesserungen gibt, und bitte teilen Sie Ihre Gedanken mit .

Hinweis : Entfernen Sie die s3-Umleitungsregeln, wenn Sie sie in der S3-Konfiguration hatten.

und übrigens funktioniert in Safari

Andrew Arnautov
quelle
hi .. danke für die lösung ... wo legst du diese nginx conf datei für die s3 bereitstellung ab. Ist es dasselbe wie elastische Bohnenstange, bei der ich den Ordner .exextensions erstellen und in die Datei proxy.config einfügen muss?
user3124360
@ user3124360 Ich bin mir nicht sicher über elastischen Beanstack, aber in meinem Fall zeige ich meinen Domainnamen auf die ec2-Instanz und habe dort die nginx-Konfiguration. Die Anfrage lautet also CLIENT -> DNS -> EC2 -> S3 -> CLIENT.
Andrew Arnautov
Ja, ich mache etwas sehr ähnliches ... mit nginx config hier github.com/davezuko/react-redux-starter-kit/issues/1099 ... danke, dass du deine conf-Datei gepostet hast. Ich sehe, wie sich diese EC2 entwickelt -> S3 Verbindung jetzt
Benutzer3124360
3

War auf der Suche nach der gleichen Art von Problem. Am Ende habe ich eine Mischung der oben beschriebenen Lösungsvorschläge verwendet.

Erstens habe ich einen S3-Bucket mit mehreren Ordnern, wobei jeder Ordner eine React / Redux-Website darstellt. Ich benutze Cloudfront auch für die Cache-Ungültigmachung.

Also musste ich Routing-Regeln zur Unterstützung von 404 verwenden und sie in eine Hash-Konfiguration umleiten:

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

In meinem js-Code musste ich mit einer baseNameKonfiguration für den React -Router umgehen . Stellen Sie zunächst sicher, dass Ihre Abhängigkeiten interoperabel sind. Ich hatte sie installiert history==4.0.0, mit denen sie nicht kompatibel war react-router==3.0.1.

Meine Abhängigkeiten sind:

  • "Geschichte": "3.2.0",
  • "reagieren": "15.4.1",
  • "React-Redux": "4.4.6",
  • "React-Router": "3.0.1",
  • "React-Router-Redux": "4.0.7",

Ich habe eine history.jsDatei zum Laden des Verlaufs erstellt:

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;

Mit diesem Code können Sie die vom Server gesendeten 404 mit einem Hash behandeln und diese im Verlauf ersetzen, um unsere Routen zu laden.

Sie können diese Datei jetzt zum Konfigurieren Ihres Geschäfts und Ihrer Root-Datei verwenden.

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;

Ich hoffe es hilft. Sie werden feststellen, dass ich bei dieser Konfiguration einen Redux-Injektor und einen Homebrew-Sagas-Injektor verwende, um Javascript asynchron über das Routing zu laden. Kümmere dich nicht um diese Zeilen.

Guillaume Cisco
quelle
3

Sie können dies jetzt mit Lambda @ Edge tun, um die Pfade neu zu schreiben

Hier ist eine funktionierende Lambda @ Edge-Funktion:

  1. Erstellen Sie eine neue Lambda-Funktion, verwenden Sie jedoch eine der bereits vorhandenen Blaupausen anstelle einer leeren Funktion.
  2. Suchen Sie nach "Cloudfront" und wählen Sie "Cloudfront-Response-Generierung" aus den Suchergebnissen aus.
  3. Ersetzen Sie nach dem Erstellen der Funktion den Inhalt durch den folgenden. Ich musste auch die Laufzeit des Knotens auf 10.x ändern, da Cloudfront zum Zeitpunkt des Schreibens Knoten 12 nicht unterstützte.
'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);
};

In Ihrem Cloudfront-Verhalten bearbeiten Sie sie, um dieser Lambda-Funktion auf "Viewer-Anforderung" einen Aufruf hinzuzufügen. Geben Sie hier die Bildbeschreibung ein

Vollständiges Tutorial: https://aws.amazon.com/blogs/compute/implementing-default-directory-indexes-in-amazon-s3-backed-amazon-cloudfront-origins-using-lambdaedge/

Loren
quelle
1
In Ihrem Codebeispiel fehlt nur eine Zeile:return callback(null, request);
Pherrymason
2

Wenn Sie hier gelandet sind und nach einer Lösung suchen, die mit React Router und AWS Amplify Console funktioniert, wissen Sie bereits, dass Sie die CloudFront-Umleitungsregeln nicht direkt verwenden können, da Amplify Console CloudFront Distribution für die App nicht verfügbar macht.

Die Lösung ist jedoch sehr einfach: Sie müssen lediglich eine Umleitungs- / Umschreiberegel in Amplify Console wie folgt hinzufügen:

Amplify Console Rewrite-Regel für React Router

Weitere Informationen (und eine kopierfreundliche Regel aus dem Screenshot) finden Sie unter den folgenden Links:

Yaro
quelle
0

Ich habe selbst nach einer Antwort gesucht. S3 scheint nur Weiterleitungen zu unterstützen. Sie können die URL nicht einfach neu schreiben und stillschweigend eine andere Ressource zurückgeben. Ich denke darüber nach, mein Build-Skript zu verwenden, um einfach Kopien meiner index.html an allen erforderlichen Pfadpositionen zu erstellen. Vielleicht funktioniert das auch für Sie.

Ed Thomas
quelle
2
Das Generieren von Indexdateien für jeden Pfad war mir ebenfalls in den Sinn gekommen, aber es wäre schwierig, dynamische Pfade wie example.com/groups/5/show zu haben . Wenn Sie meine Antwort auf diese Frage sehen, glaube ich, dass dies das Problem zum größten Teil löst. Es ist ein bisschen wie ein Hack, aber zumindest funktioniert es.
Mark Nutter
Besser hinter einem Nginx-Server bereitstellen und index.html für alle eingehenden URLs zurückgeben. Ich habe dies erfolgreich mit der Heroku-Bereitstellung von Ember-Apps gemacht.
Moha297
-3

Nur um die extrem einfache Antwort zu formulieren. Verwenden Sie einfach die Hash-Standortstrategie für den Router, wenn Sie auf S3 hosten.

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

Meester vorbei
quelle