wake-up-neo.com

S3 Static Website Hosting Route alle Pfade nach Index.html

Ich verwende S3 zum Hosten einer Javascript-App, die HTML5-PushStates verwendet. Das Problem besteht darin, dass der Benutzer eine der URLs mit einem Lesezeichen versehen kann. Was ich brauche, ist die Fähigkeit, alle URL-Anforderungen anzunehmen 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 liefern. 

Gibt es eine Möglichkeit, S3 mitzuteilen, die index.html für alle URL-Anforderungen bereitzustellen, anstatt Weiterleitungen durchzuführen? Dies ähnelt dem Einrichten von Apache für die Verarbeitung aller eingehenden Anforderungen, indem eine einzelne index.html wie in diesem Beispiel bereitgestellt wird: https://stackoverflow.com/a/10647521/1762614 . Ich möchte es wirklich vermeiden, einen Webserver auszuführen, um diese Routen zu bewältigen. Alles aus S3 zu machen ist sehr ansprechend. 

193
Mark Nutter

Ich konnte das so zum Laufen bringen:

Fügen Sie im Bereich Edit Umleitungsregeln der S3-Konsole für Ihre Domäne die folgenden Regeln hinzu:

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

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

Um HTML5-PushStates verwenden zu können, müssen wir jedoch diese Anforderung annehmen und manuell den richtigen PushState basierend auf dem Hash-Bang-Pfad festlegen. Fügen Sie dies dem Anfang Ihrer index.html-Datei hinzu:

<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 Pfade ohne Hash-Bang in Ihrer App zu verwenden.

190
Mark Nutter

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

  • Erstellen Sie beispielsweise einen S3-Bucket: Reagieren
  • Erstellen Sie CloudFront-Distributionen mit diesen Einstellungen:
    • Standardstammobjekt : index.html
    • Origin Domain Name : S3-Bucket-Domain, zum Beispiel: react.s3.amazonaws.com
  • Gehen Sie zur Registerkarte Error Pages , und klicken Sie auf Create User Error Response :
    • HTTP-Fehlercode : 403: Verboten (404: Nicht gefunden, im Falle einer statischen S3-Website)
    • Fehlerantwort anpassen : Ja
    • Antwortseitenpfad : /index.html
    • HTTP-Antwortcode : 200: OK
    • Klicken Sie auf Erstellen
179
lenaten

Es gibt nur wenige Probleme mit dem S3/Redirect-basierten Ansatz, der von anderen erwähnt wurde.

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

Die Lösung ist:

  1. Stellen Sie sicher, dass Sie die Indexroute für Ihre Website konfiguriert haben. Meist ist es index.html
  2. Entfernen Sie Routing-Regeln aus S3-Konfigurationen
  3. Stellen Sie eine Cloudfront vor Ihren S3-Eimer. 
  4. Konfigurieren Sie Fehlerseitenregeln für Ihre Cloudfront-Instanz. Geben Sie in den Fehlerregeln Folgendes an:
    • HTTP-Fehlercode: 404 (und 403 oder andere Fehler je nach Bedarf)
    • Fehler-Caching Minimum TTL (Sekunden): 0
    • Antwort anpassen: Ja
    • Antwortseitenpfad: /index.html
    • HTTP-Antwortcode: 200

5.Für SEO-Anforderungen müssen Sie Folgendes sicherstellen: Stellen Sie sicher, 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-Adresse zu.
  • Erstellen Sie eine ELB, deren EC2-Instanz Sie als Instanz erstellt haben
  • Sie sollten die ELB Ihrem DNS zuweisen können.
  • Konfigurieren Sie nun Ihren Nginx-Server für die folgenden Aufgaben: Proxy_Pass alle Anforderungen an Ihr CDN (nur für index.html, bedienen Sie andere Assets direkt von Ihrer Cloud aus) und leiten Sie den Datenverkehr für Such-Bots wie von Prerender.io festgelegt um

Ich kann in Bezug auf das Nginx-Setup in mehr Details helfen, einfach eine Notiz hinterlassen. Habe es auf die harte Tour gelernt.

Sobald die Cloud-Front-Distribution aktualisiert wurde. Machen Sie Ihren Cloudfront-Cache einmal für ungültig, um sich im unberührten Modus zu befinden ..

120
moha297

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

Angenommen, ein Benutzer besucht /foo/bear auf Ihrer von S3 gehosteten statischen Website. Wenn Davidsfrüherer Vorschlag vorliegt, werden die Umleitungsregeln an /#/foo/bear gesendet. Wenn Ihre Anwendung anhand des Browserverlaufs erstellt wurde, kann dies nicht viel nützen. Ihre Anwendung wird jedoch zu diesem Zeitpunkt geladen und kann nun den Verlauf bearbeiten.

Wenn Sie Rackt history in unser Projekt aufnehmen (siehe auch Using Custom Histories aus dem React Router-Projekt), können Sie einen Listener hinzufügen, der die Hash-Verlaufspfade kennt, und den Pfad gegebenenfalls als ersetzen illustriert in diesem Beispiel:

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

  1. Davids S3-Umleitungsregel leitet /foo/bear an /#/foo/bear.
  2. Ihre Anwendung wird geladen.
  3. Der History-Listener erkennt die #/foo/bear-History-Notation.
  4. Und ersetzen Sie die Geschichte durch den richtigen Pfad.

Link tags funktioniert wie erwartet, ebenso wie alle anderen Browserverlaufsfunktionen. Der einzige Nachteil, den ich bemerkt habe, ist die Interstitial-Umleitung, die bei der ersten Anforderung auftritt.

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

14
Michael Ahlers

Ich sehe 4 Lösungen für dieses Problem. Die ersten 3 waren bereits in Antworten enthalten und der letzte ist mein Beitrag.

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

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

  3. CloudFront konfigurieren.
    Problem: Alle Seiten geben 404 von Origin zurück. Sie müssen also auswählen, ob Sie nichts zwischenspeichern möchten (TTL 0 wie vorgeschlagen) oder ob beim Zwischenspeichern Probleme auftreten, wenn Sie die Site aktualisieren.

  4. Prerender alle Seiten.
    Problem: Zusätzliche Arbeit für Prerender-Seiten, insbesondere wenn sich die Seiten häufig ändern. Zum Beispiel eine Nachrichten-Website.

Mein Vorschlag ist, die Option 4 zu verwenden. Wenn Sie alle Seiten vorrenderieren, werden für erwartete Seiten keine 404-Fehler angezeigt. Die Seite wird gut geladen und das Framework übernimmt die Kontrolle und fungiert normalerweise 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 den Hashbang) angezeigt wird.

Bei 403 verbotenen Fehlern lasse ich sie überhaupt nicht passieren. In meiner Anwendung halte ich fest, dass all -Dateien im Host-Bucket öffentlich sind, und ich setze dies mit der Option jeder mit der Berechtigung read. Wenn Ihre Site über private Seiten verfügt, sollte es für den Benutzer kein Problem sein, den HTML-Code layout anzuzeigen. Was Sie schützen müssen, ist das data, und dies geschieht im Backend.

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

10
Zanon

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

In der Tat müssen Sie zu Edit Permissions gehen, klicken Sie auf Weitere Berechtigungen hinzufügen und fügen Sie dann jedem die richtige List in Ihrem Bucket hinzu. Mit dieser Konfiguration kann AWS S3 jetzt den 404-Fehler zurückgeben, und die Umleitungsregel fängt den Fall richtig ein.

Genau wie dieser :  enter image description here

Und dann können Sie zu Umleitungsregeln bearbeiten gehen und diese 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 HostName subdomain.domain.fr durch Ihre Domäne und KeyPrefix #!/Ersetzen, wenn Sie die Hashbang-Methode nicht für SEO-Zwecke verwenden.

Natürlich funktioniert das alles nur, wenn Sie in Ihrer Winkelanwendung bereits html5mode eingerichtet haben.

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

Die einfachste Lösung für die Bereitstellung der Angular 2+ -Anwendung über Amazon S3 und für direkte URLs besteht darin, index.html als Index- und Fehlerdokument in der S3-Bucket-Konfiguration anzugeben.

 enter image description here

6

da das problem immer noch da ist, habe ich zwar eine andere lösung eingeworfen ..__ Mein Fall war, dass ich alle Pull-Anforderungen vor dem Zusammenführen auf s3 zum Testen bereitstellen wollte, um sie unter [meineDomäne]/pull-request/[PR-Nummer verfügbar zu machen ] /
(ex. www.example.com/pull-requests/822/)

Nach bestem Wissen würden Szenarien mit Ausnahme von S3-Regeln es ermöglichen, mehrere Projekte in einem Bucket mit Hilfe von html5-Routing zu haben. Wenngleich die meisten Abstimmungsvorschläge für ein Projekt im Stammordner funktionieren, gilt dies nicht für mehrere Projekte in eigenen Unterordnern.

Also habe ich meine Domain auf meinen Server verwiesen, auf den die folgende nginx config folgte

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 wird versucht, die Datei abzurufen, und wenn dies nicht der Fall ist, wird davon ausgegangen, dass es sich um eine html5-Route handelt. Wenn Sie eine 404-Winkelseite für nicht gefundene Routen haben, werden Sie nie zu @not_found gelangen und erhalten eine eckige 404-Seite statt nicht gefundener Dateien. Dies kann durch eine if-Regel in @get_routes oder so behoben werden.

Ich muss sagen, ich fühle mich im Bereich von nginx config und der Verwendung von Regex nicht allzu wohl. Ich habe dieses Problem mit Versuch und Irrtum gelöst. Während dies funktioniert, bin ich sicher, dass es Raum für Verbesserungen gibt und bitte teilen Sie Ihre Gedanken mit .

Hinweis : Entfernen Sie s3-Umleitungsregeln, wenn Sie sie in S3 config hatten.

und übrigens funktioniert in Safari

4
Andrew Arnautov

War auf der Suche nach dem gleichen Problem ... Ich habe am Ende eine Mischung der oben beschriebenen Lösungsvorschläge verwendet.

Erstens habe ich einen s3-Bucket mit mehreren Ordnern, wobei jeder Ordner eine Website fürreact/redux darstellt Ich verwende auch Cloudfront für die Cache-Ungültigmachung.

Daher musste ich Routing Rules verwenden, um 404 zu unterstützen, und sie an eine Hash-Config 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 es mit einer baseName config für den reakt-router ..__ behandeln. Stellen Sie zunächst sicher, dass Ihre Abhängigkeiten interoperabel sind. Ich hatte history==4.0.0 installiert, der mit react-router==3.0.1 nicht kompatibel war.

Meine Abhängigkeiten sind:

  • "history": "3.2.0",
  • "reagieren": "15.4.1",
  • "Reakt-Redux": "4.4.6"
  • "Reakt-Router": "3.0.1",
  • "Reakt-Router-Redux": "4.0.7",

Ich habe eine history.js-Datei 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;

Dieser Code ermöglicht es, die vom Server gesendeten 404 mit einem Hash zu behandeln und in der Historie für das Laden unserer Routen zu ersetzen.

Sie können diese Datei jetzt zum Konfigurieren Ihres Geschäfts und Ihrer Stammdatei 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. Mit dieser Konfiguration verwende ich den Redux-Injektor und einen Homebrew-Sagas-Injektor, um Javascript asynchron über das Routing zu laden.

3
Guillaume Cisco

Wenn Sie auf der Suche nach einer Lösung gelandet sind, die mit React Router und AWS Amplify Console funktioniert, wissen Sie bereits, dass Sie 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 in Amplify Console lediglich eine Umleitungs-/Umschreibungsregel wie die folgende hinzufügen:

Amplify Console Rewrite rule for React Router

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

1
Yaro

Ich habe selbst nach einer Antwort darauf gesucht. S3 scheint nur Umleitungen zu unterstützen. Sie können die URL nicht einfach neu schreiben und eine andere Ressource im Hintergrund zurückgeben. Ich erwäge, mein Build-Skript zu verwenden, um einfach Kopien meiner index.html in allen erforderlichen Pfadpositionen zu erstellen. Vielleicht klappt das auch für Sie.

0
Ed Thomas

Dies ist die eleganteste Lösung , die ich gefunden habe - verwenden Sie das App-Routermodul mit einer Wildcard-Weiterleitung.

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

Stellen Sie dann, wie in den unzähligen Beiträgen oben erwähnt, sicher, dass Sie 404/403-Fehler zu index.html mit dem Status 200 umleiten. Das Problem ist, dass dies zu einem Browser-Refresh führt, bei dem die Basis-Href als (Href + vorherige Route) geladen wird. Wenn Sie sich die Router-Ansicht unter angesehen haben

www.my-app.com/home dann wird die Aktualisierung angezeigt

www.my-app.com/home/home

Um den Pfad der doppelten Route zu entfernen, verwenden Sie das Modul APP_BASE_HREF, um die Browserbasis href einfach neu zuzuweisen.

Wenn Sie den ersten URL-Parameter beibehalten müssen, hängen Sie mehrere Ergebnisse aus der '/'-Aufteilung an.

Browser-Treffer für Ihre SPA-Weiterleitung für www.your-app.com/home/home ersetzen jetzt die URL durch www.your-app.com/home und die App verhält sich wie erwartet von Ihrer In-App-Routing-Konfiguration

0
Chris Concannon

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

0
Meester Over