Der React Router funktioniert nicht im aws s3 Bucket

74

Ich habe meinen React- build/Websiteordner in einem AWS S3-Bucket bereitgestellt .

Wenn ich zu gehe www.mywebsite.com, funktioniert es und wenn ich auf aTag klicke, um zu den Seiten Projekt und Info zu gelangen, werde ich zur richtigen Seite weitergeleitet. Wenn ich jedoch die Seiten-URL kopiere und sende oder direkt zu dem Link gehe wie : www.mywebsite.com/projects, wird 404 zurückgegeben.

Hier ist mein App.jsCode:

const App = () => (
    <Router>
        <div>
            <NavBar/>
            <Switch>
                <Route exact path="/" component={Home}/>
                <Route exact path="/projects" component={Projects}/>
                <Route exact path="/about" component={About}/>
                <Route component={NoMatch}/>
            </Switch>
        </div>
    </Router>
);
Viet
quelle
3
Ich denke nicht, dass dies ein Problem mit React Router ist, sondern dass Ihr Server Ihre index.htmlund bundle.jskeine andere Route als bedient /. Diese Dateien müssen auf allen Routen bereitgestellt werden.
Tholle
7
Möglicher Betrug von stackoverflow.com/a/23544903/5079258 . Sie müssen Fehler (in diesem Fall 404) an die Wurzel umleitenindex.html
Alan Friedman
1
Hey @ Alan Friedman. Das ist für mich in Ordnung.
Viet

Antworten:

104

Ich bin mir nicht sicher, ob Sie es bereits gelöst haben. Ich hatte das gleiche Problem.

Dies liegt daran, dass AWS S3 nach dem Ordner (den Projekten) sucht, aus dem Sie dienen können, den Sie nicht haben.

Zeigen Sie einfach auf Fehlerdokument auf index.html.

Geben Sie hier die Bildbeschreibung ein

Das hat bei mir funktioniert. Sie können Fehlerseiten im React-Router behandeln.

AR Naseef
quelle
Danke, AR. Ja, ich habe es dank Alan Friedmans Kommentar oben gelöst.
Viet
15
Kleinigkeiten. Wenn ich auf einen Pfad stoße, wird in der Konsole 404 nicht gefunden angezeigt, da wir ihn auf die Fehlerseite umleiten. Ich bin nicht überzeugt. Es könnte einen besseren Weg geben.
AR Naseef
1
Ja. Dies ist offensichtlich ein Hack. Für die richtige Lösung müssen Sie möglicherweise S3-Umleitungsregeln hinzufügen. Versuchen Sie auch, HashRouter (anstelle von BrowserRouter) vom React-Router zu verwenden. Dies könnte funktionieren
AR Naseef
1
@LuisGouveia wie bist du dann weitergegangen? Was haben Sie gemacht?
Sumanth Shetty
1
@sumanthshetty überprüfe meinen Kommentar zu "Amr Abu Greedah" Antwort! Einen schönen Tag noch
Luis Gouveia
51

Update 1. Mai 2020:

Da dieser Beitrag ziemlich aktiv ist, muss ich die Antwort aktualisieren:

Sie haben also einige Möglichkeiten, um das Problem zu lösen:

  1. Sie können setzen index.html im Fehler Dokument Feld (wie Alan Friedman vorgeschlagen).
    • Gehen Sie zu Ihrem Bucket (dem, der tatsächlich den Code enthält - nicht dem, den Sie zum Umleiten verwenden) -> Eigenschaften -> Statisches Website-Hosting :
    • Dies ist nicht "hacky", aber es funktioniert aufgrund der Funktionsweise react-router : Es verarbeitet die Anforderungen vom Front-End und leitet Benutzer zu anderen Routen weiter. Insgesamt ist die React-App jedoch eine einseitige Anwendung.
    • Wenn Sie serverseitig reagieren möchten, sollten Sie Next.js verwenden .

Geben Sie hier die Bildbeschreibung ein

  1. Sie können eine bestimmte Fehlerdatei setzen error.html in den öffentlichen Reaktion App Ordner Ihrer und in der statischen Website - Hosting : Fehler Dokument Feld setzte in: error.html . Das funktioniert auch. Ich habe es getestet.

  2. Verwenden Sie AWS CloudFront > CloudFront-Verteilungen > Die Verteilung Ihres Buckets> Fehlerseiten und fügen Sie den gewünschten Fehlercode hinzu. Wenn Sie nicht verwenden react-router(wie im folgenden Beispiel), antwortet der Bucket mit Fehler 403, sodass Sie mit Ihrer error.html antworten können .

Geben Sie hier die Bildbeschreibung ein

  1. Wird TypeScriptderzeit react-routernicht unterstützt, daher sollten Sie Option 2 und 3 in Betracht ziehen . Sie werden die Bibliothek in einer zukünftigen Version 6.*gemäß diesem Thread aktualisieren .
Viet
quelle
2
Das ist sehr hackig, aber auch die Lösung, die ich benutze. Was ich daran nicht mag, ist, dass der 404 immer noch passiert, er wird nur umgeleitet.
ThisGuyCantEven
src="/static/somescript.js"Beachten Sie eine Konsequenz davon: Wenn Ihre Webseite eine enthält, in der somescript.js nicht vorhanden ist oder in der der Zugriff auf das angeforderte Skript verweigert wird, liefert die Anforderung des Browsers eher den Inhalt der Datei index.html als die JS-Datei und diese wird vom Browser als JavaScript analysiert und führt zu JavaScript-Analysefehlern von "<! doctype html> ...". Ähnlich für CSS-Dateien oder andere Assets.
Jarmod
2
Diese Lösung wirkt sich auf SEO aus. Google bewertet Websites, die 404s werfen, nicht gut.
Luis Gouveia
13

Falls dieser S3-Bucket von einer CloudFront-Distribution bereitgestellt wird :

Erstellen Sie eine benutzerdefinierte Fehlerseite (AWS Docs) in der CloudFront-Distribution, die 404-Fehler an index.html weiterleitet und 200 Antwortcode zurückgibt. Auf diese Weise übernimmt Ihre Anwendung das Routing.

Benutzerdefinierte Fehlerseiten

Geben Sie hier die Bildbeschreibung ein

Meir Gabay
quelle
2
JA, ich musste auch 403 hinzufügen
arthurakay
Hätte dies nicht das unerwünschte Verhalten, legitime 404s an index.html weiterzuleiten, auch für Bilder usw.? Manchmal möchten Sie eine echte 404.
cbp
Das ist die Idee hinter "Ihre Anwendung wird das Routing verwalten". Jede Anforderung durchläuft Ihre index.html (einseitige Anwendung) und der Router Ihrer Anwendung gibt die entsprechende Antwort zurück. Dies bedeutet, dass Sie die Routing-Logik in der App selbst behalten und gleichzeitig die Wartung einer anderen Routing-Logik in CloudFront vermeiden. Dies ist nur ein netter Trick, der das Leben des Entwicklers erleichtert - Routing als One-Stop-Shop, keine Notwendigkeit, etwas über AWS zu wissen
Meir Gabay
Nun, außer dass Ihre Anwendung in diesem Fall clientseitig und nicht serverseitig ist. Als "Anwendung" können Sie daher nicht mehr signalisieren, dass eine Ressource nicht gefunden wurde. Ich denke, Sie sollten zwischen Routen und Dateien unterscheiden, die von der Anwendung verarbeitet werden, und Routen, die von S3 oder Cloudfront verarbeitet werden.
Froginvasion
10

Das Umleiten von 4xx zu index.html würde funktionieren, aber diese Lösung würde dazu führen, dass Sie auf viele andere Probleme stoßen, z. B. dass Google diese Seiten nicht crawlen kann. Bitte überprüfen Sie diesen Link . Dieses Problem wurde mithilfe von Umleitungsregeln für den S3-Bucket behoben.

Amr Abu Greedah
quelle
4
Deine Antwort rockt! Es sollte die akzeptierte Antwort sein, da die akzeptierte nicht optimal ist und sehr unangenehme Auswirkungen auf die Suchmaschinenoptimierung hat (weil Google keine Websites mag, die 404s zurückgeben). Wenn jemand @Amr Abu Greedah-Äquivalent für die Microsoft-Welt sucht, empfehle ich, die folgende Antwort zu überprüfen: stackoverflow.com/a/50767709/3231884
Luis Gouveia
Nur für den Fall, dass die Verwendung des XML-Formats fehlschlägt, versuchen Sie, eine JSON-Version für Ihre Umleitungsregeln zu verwenden. Das musste ich tun, damit diese Lösung für mich funktioniert
Nick
6

Fall verwenden Cloudfront zu S3:

https://hackernoon.com/hosting-static-react-websites-on-aws-s3-cloudfront-with-ssl-924e5c134455

3b) AWS CloudFront - Fehlerseiten Fahren Sie nach dem Erstellen der CloudFront-Distribution mit dem Status "In Bearbeitung" mit der Registerkarte "Fehlerseiten" fort. Behandeln Sie die Antwortcodes 404 und 403 mit "Fehlerantwort anpassen".

Google empfiehlt 1 Woche oder 604800 Sekunden Caching. Wir richten hier CloudFront so ein, dass fehlende HTML-Seiten behandelt werden. Dies tritt normalerweise auf, wenn ein Benutzer einen ungültigen Pfad eingibt oder insbesondere einen anderen Pfad als den Stammpfad aktualisiert.

Wenn das passiert:

CloudFront sucht nach einer Datei, die im S3-Bucket nicht vorhanden ist. Es befindet sich nur 1 HTML-Datei im Bucket. Dies ist die index.html für den Fall einer Einzelseitenanwendung wie dieses Projektbeispiel. Eine 404-Antwort wird zurückgegeben und von unserem benutzerdefinierten Fehlerantwort-Setup entführt. Wir werden stattdessen einen 200-Antwortcode und die index.html-Seite zurückgeben. Der React-Router, der zusammen mit der Datei index.html geladen wird, überprüft die URL und rendert die richtige Seite anstelle des Stammpfads. Diese Seite wird für die Dauer der TTL für alle Anforderungen an den abgefragten Pfad zwischengespeichert. Warum müssen wir auch mit 403 umgehen? Dies liegt daran, dass dieser Antwortcode anstelle von 404 von Amazon S3 für nicht vorhandene Assets zurückgegeben wird. Zum Beispiel eine URL von https://yourdomain.com/somewhere wird nach einer Datei suchen, die irgendwo (ohne Erweiterung) aufgerufen wird und nicht existiert.

PS. Früher gab es 404 zurück, aber jetzt scheint es 403 zurückzugeben; In beiden Fällen ist es am besten, beide Antwortcodes zu verarbeiten.

Flávio Vieira
quelle
Das hat bei mir funktioniert. Es ist das gleiche wie stackoverflow.com/a/52343542/2624935, aber für Cloudfront
Pnar Sbi Wer
Das hat funktioniert! Durch viele Artikel zu diesem Thema war der 403 das fehlende Glied - danke
Chris Webb
Im Gegensatz zu dem, was der Artikel sagt, gilt dies nicht nur für HTML-Seiten. Jeder 404, auch für Bilder usw., leitet index.html um, was ziemlich hässlich ist.
cbp
5

Diese Frage hat bereits mehrere gute Antworten. Obwohl die Frage jetzt alt ist, habe ich mich heute diesem Problem gestellt, daher habe ich das Gefühl, dass diese Antwort vielleicht helfen kann.

S3 verfügt über zwei Arten von Endpunkten. Wenn dieser Fehler auftritt, haben Sie wahrscheinlich den S3-Bucket direkt als Endpunkt im Feld Ursprungsdomänenname für Ihre CloudFront-Verteilung ausgewählt.

Das würde ungefähr so ​​aussehen: bucket-name.s3.amazonaws.com und ist ein vollkommen gültiger Endpunkt. Tatsächlich scheint AWS dies als Standardverhalten zu erwarten. Dieser Eintrag befindet sich in der Dropdown-Liste, die Sie beim Erstellen Ihrer CloudFront-Distribution haben.

Wenn Sie dies jedoch tun und dann Fehlerseiten einstellen, kann dies Ihr Problem möglicherweise lösen oder nicht.

S3 verfügt jedoch über einen dedizierten Website-Endpunkt. Sie können über Ihren S3-Bucket> Eigenschaften> Statisches Website-Hosting darauf zugreifen. (Sie sehen den Link oben).

Sie sollten diesen Link anstelle des ursprünglichen automatisch ausgefüllten Links verwenden, der in CloudFront angezeigt wird. Sie können dies beim Erstellen Ihrer Distribution eingeben oder nach der Erstellung über die Registerkarte Ursprünge und Ursprungsgruppen bearbeiten und anschließend die Caches ungültig machen.

Dieser Link sieht folgendermaßen aus : bucket-name.s3-website.region-name.amazonaws.com.

Sobald sich dies verbreitet und ändert, sollte dies Ihr Problem beheben.

tl; dr: Verwenden Sie nicht den Standard-S3-Endpunkt in CloudFront. Verwenden Sie stattdessen den S3-Website-Endpunkt. Ihre Ursprungsdomäne sollte so aussehen: my-application.s3-website.us-east-1.amazonaws.comund nicht so my-application.s3.amazonaws.com.

Weitere Informationen zu Website-Endpunkten finden Sie in der AWS-Dokumentation hier .

jethroFloyd
quelle
Das funktioniert. Aber warum brauchen Sie dann Cloudfront und profitieren von SSL und der Verteilung in mehreren Regionen?
Patrick Bassut
1

Warum es passiert

Ihr Problem ist, dass Sie die Verantwortung für das Routing an Ihre Reaktions-App / Ihr Javascript übertragen möchten. Der Link funktioniert, da reagieren den Linkklick abhören und einfach die Route in der Browser-URL-Leiste aktualisieren kann. Wenn Sie jedoch an einen Ort gehen, an dem Ihr Skript (index.html und bundle.js oder wo sich Ihr App-Code befindet) nicht geladen ist, wird das JavaScript nie geladen und hat keine Chance, die Anforderung zu bearbeiten. Unabhängig davon, was auf Ihrem Server ausgeführt wird, wird die Anforderung bearbeitet. Überprüfen Sie, ob sich an dieser Stelle eine Ressource befindet, und geben Sie einen 404-Fehler oder einen anderen gefundenen Fehler zurück.

Die Lösung

Wie in den Kommentaren erwähnt, ist dies der Grund, warum Sie 404-Fehler an den genauen Ort umleiten müssen, an dem Ihre App platziert ist. Dies ist nichts Besonderes für Amazon. Es ist eine allgemeine Voraussetzung, um Ihre Reaktions-App einzurichten.

Um das Problem zu lösen, müssen Sie herausfinden, wie das Routing auf Ihrem Server funktioniert und wie es konfiguriert wird. Wenn Sie beispielsweise einen Apache-Server haben, kann sich eine .htaccess-Datei wie folgt um Folgendes kümmern:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>

Mit dieser Datei kann der Server nicht gefundene Fehler in die Datei index.html umleiten. Beachten Sie, dass dies möglicherweise Auswirkungen auf andere Routing-Regeln auf Ihrem Server hat. Daher ist diese Konfiguration am einfachsten, wenn Ihre Reaktions-App einen eigenen Platz hat und andere Dinge nicht beeinträchtigt.

Gegenwind
quelle
Das heißt also, ich erhalte jedes Mal eine http-Anfrage, wenn ich auf einen Link in React klicke?
Itay Moav-Malimovka
1
@ ItayMoav-Malimovka Nein, das ist nicht der Fall. Dies geschieht nur, wenn Sie die Anwendung / den Typ in die ursprüngliche URL eingeben. Hier entscheidet der Server, was an den Client gesendet werden soll - in diesem Fall die React-App. Von da an übernimmt der React-Router und ändert die angezeigte URL, den Verlauf usw., ohne dass der Server dies weiß.
Gegenwind
6
Hier geht es um das Routing auf S3. kein Server dazwischen
mithril_knight
1

Ich bin auf dieses Problem gestoßen, obwohl ich die in der akzeptierten Antwort beschriebene Konfiguration verwendet habe. Wenn jedoch immer noch 403 Fehler angezeigt werden und Sie AWS Cloudflare Manager verwenden, können Sie auf der Registerkarte "Fehlerseiten" der Verteilungseinstellungen eine Fehlerseite erstellen , mit folgender Konfiguration:

Error Code: 404,
Customize Error Response: Yes, 
Response Page Path: /index.html, 
HTTP Response Code: 200

Bild der Fehlerseite Konfigurieren Sie, um die Routenbehandlung an den Browser-Router zu übergeben

Dies hat bei mir funktioniert, obwohl ich keineswegs über den richtigen Serveradministrator Bescheid weiß. Hoffentlich wird mir jemand sagen, ob dies ein großes Problem ist, wenn es zufällig ist.

Dank
quelle
403 = verboten. Sind Sie sicher, dass Ihr Eimer oder Objekt öffentlich ist?
Viet
1
Ich habe dasselbe getan wie @worc: CloudFront> Fehlerseiten> Benutzerdefinierte Fehlerantwort erstellen> 403 oder 404, abhängig von Ihrem Fehler> Fehlerantwort anpassen: Ja> Antwortseitenpfad: /index.html> HTTP-Antwortcode: 200
Sven Möhring
Sie werden in der Cloud-Front einen Fehler X-Cache-Fehler von der Cloudfront haben
Chemitaxis
0

Ich habe es behoben, indem ich HashRouteranstelle von verwendet habeRouter

import { Switch, Route, HashRouter } from 'react-router-dom';

const App = () => (
    <HashRouter>
        <div>
            <NavBar/>
            <Switch>
                <Route exact path="/" component={Home}/>
                <Route exact path="/projects" component={Projects}/>
                <Route exact path="/about" component={About}/>
                <Route component={NoMatch}/>
            </Switch>
        </div>
    </HashRouter>
);

Die App ist von so etwas wie zugänglich https://your-domain.s3.amazonaws.com/index.html?someParam=foo&otherPram=bar/#/projects

auf localhost wie https://localhost:3000/?someParam=foo&otherPram=bar/#/projects

Es waren keine Änderungen in S3 erforderlich.

BezobidnijPsih
quelle
Sieht nach einer schnellen und ordentlichen Lösung aus. Aber achten Sie auf! In ihrer Dokumentation wird empfohlen, stattdessen Ihren Server zu konfigurieren: "WICHTIGER HINWEIS: Der Hash-Verlauf unterstützt nicht location.key oder location.state. In früheren Versionen haben wir versucht, das Verhalten zu korrigieren, aber es gab Randfälle, die wir nicht lösen konnten Code oder Plugin, die dieses Verhalten benötigen, funktionieren nicht. Da diese Technik nur ältere Browser unterstützen soll, empfehlen wir Ihnen, Ihren Server so zu konfigurieren, dass er stattdessen mit <BrowserHistory> funktioniert. " reactrouter.com/web/api/HashRouter
wojjas
0

Ich benutze NextJS und hatte das gleiche Problem. Meine Lösung bestand darin, die Routing-Informationen zu überprüfen und zu pushen, wenn sie nicht passen.

const router = useRouter();
useEffect(() => {
    if (!router.pathname.startsWith(router.asPath)) {
      router.push(router.asPath);
    }
  });

Auf der S3-Seite musste nichts geändert werden, außer dass die Fehlerseite an index.html weitergeleitet wurde

Bnaya
quelle
-1

Wie in den vorherigen Antworten angegeben, ist der beste Weg, um das Problem zu lösen: Definieren Sie die Fallback-Strategie neu. Wenn Sie mehr über clientseitiges Routing und serverseitiges Routing und insbesondere über verschiedene Routing-Ansätze in React JS erfahren möchten, lesen Sie diesen Artikel .

Val
quelle
Diese Lösung scheint unter einigen Problemen zu leiden: 1) Obwohl der Seiteninhalt korrekt zurückgegeben wird, lautet der http-Antwortcode immer noch 404. 2) Er erfasst 404 Anforderungen für Dinge wie Bilder usw. und
leitet
Guter Anruf, wenn es ein Problem ist, würde ich vorschlagen, Umleitungsregeln, Umleitungsregeln , zu verwenden . Eine Zeile unterhalb der Fehlerseitenkonfiguration. Beispiel 3: Eine Umleitung für einen HTTP-Fehler aus dem Dokument wäre ein guter Startpunkt. In dem <Condition>Teil können wir so etwas hinzufügen <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>. Und alle Anfragen sollten 301 sein.
Val