it-swarm.com.de

React-Router-URLs funktionieren nicht, wenn Sie manuell aktualisieren oder schreiben

Ich verwende den React-Router und er funktioniert gut, während ich auf die Link-Schaltflächen klicke, aber wenn ich meine Webseite aktualisiere, wird nicht geladen, was ich möchte.

Zum Beispiel bin ich in localhost/joblist und alles ist in Ordnung, weil ich hier angekommen bin und auf einen Link geklickt habe. Wenn ich jedoch die Webseite aktualisiere, bekomme ich: GET/joblist nicht erhalten

Standardmäßig hat es nicht so funktioniert. Anfangs hatte ich meine URL: localhost/#/und localhost/#/joblist und sie funktionierten einwandfrei. Aber ich mag diese Art von URL nicht, also versuche ich das # zu löschen, das ich geschrieben habe:

Router.run(routes, Router.HistoryLocation, function (Handler) {
 React.render(<Handler/>, document.body);
});

Dieses Problem tritt bei localhost/nicht auf, dieses gibt immer das zurück, was ich will.

BEARBEITEN: Diese App ist eine Einzelseite, so dass/joblist keinen Server fragen muss.

EDIT2: Mein gesamter Router.

var routes = (
    <Route name="app" path="/" handler={App}>
        <Route name="joblist" path="/joblist" handler={JobList}/>
        <DefaultRoute handler={Dashboard}/>
        <NotFoundRoute handler={NotFound}/>
    </Route>
);

Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});
407
DavidDev

Wenn ich mir die Kommentare zur akzeptierten Antwort und den allgemeinen Charakter dieser Frage („Funktioniert nicht“) anschaue, denke ich, dass dies ein guter Ort für einige allgemeine Erklärungen zu den hier auftretenden Problemen sein könnte. Diese Antwort ist also als Hintergrundinformation/-ausarbeitung für den spezifischen Anwendungsfall des OP gedacht. Bitte bei mir tragen.

Serverseitig vs clientseitig

Das erste große Problem dabei ist, dass es jetzt zwei Stellen gibt, an denen die URL interpretiert wird, während es früher nur eine gab. In der Vergangenheit, als das Leben einfach war, sandte ein Benutzer eine Anfrage nach http://example.com/about An den Server, der den Pfadteil der URL überprüfte, feststellte, dass der Benutzer die About-Seite anforderte, und schickte dann diese Seite zurück.

Mit dem clientseitigen Routing, das von React-Router bereitgestellt wird, sind die Dinge weniger einfach. Der Client hat zunächst noch keinen JS-Code geladen. Die allererste Anfrage wird also immer an den Server gerichtet. Daraufhin wird eine Seite zurückgegeben, die die erforderlichen Skript-Tags zum Laden von React und React Router usw. enthält. Erst wenn diese Skripts geladen wurden, wird Phase 2 gestartet. Wenn der Benutzer in Phase 2 beispielsweise auf den Navigationslink "Über uns" klickt, wird die URL geändert nur lokal in http://example.com/about (Ermöglicht durch History API ), aber keine Anfrage an den Server gestellt . Stattdessen erledigt der React Router seine Aufgabe auf der Clientseite und bestimmt, welche React Ansicht gerendert und gerendert werden soll. Angenommen, Ihre About-Seite muss keine REST Aufrufe ausführen, dann ist dies bereits geschehen. Sie sind von Home zu About Us gewechselt, ohne dass eine Serveranforderung ausgelöst wurde.

Wenn Sie also auf einen Link klicken, wird Javascript ausgeführt, das die URL in der Adressleiste manipuliert, ohne eine Seitenaktualisierung zu verursachen, was wiederum dazu führt, dass React Router einen Seitenübergang durchführt auf der Client-Seite .

Überlegen Sie nun, was passiert, wenn Sie die URL in die Adressleiste kopieren und per E-Mail an einen Freund senden. Ihr Freund hat Ihre Website noch nicht geladen. Mit anderen Worten, sie ist immer noch in Phase 1. Auf ihrem Computer läuft noch kein React Router. Ihr Browser sendet also eine Serveranfrage an http://example.com/about.

Und hier beginnt Ihr Ärger. Bis jetzt konnten Sie mit dem Platzieren eines statischen HTML-Codes an der Wurzel Ihres Servers davonkommen. Dies würde jedoch zu 404 - Fehlern für alle anderen URLs führen wenn vom Server angefordert. Dieselben URLs funktionieren einwandfrei auf der Clientseite, da der React Router das Routing für Sie übernimmt, aber sie schlagen fehl auf der Serverseite es sei denn, Sie bringen Ihren Server dazu, sie zu verstehen.

Server- und clientseitiges Routing kombinieren

Wenn die URL http://example.com/about Sowohl auf der Server- als auch auf der Clientseite funktionieren soll, müssen Sie auf der Server- und der Clientseite Routen dafür einrichten. Macht das Sinn oder?

Und hier beginnen Ihre Entscheidungen. Die Lösungen reichen von der Umgehung des Problems insgesamt über eine Catch-All-Route, die den HTML-Code bootstrap zurückgibt, bis hin zum vollständig isomorphen Ansatz, bei dem sowohl der Server als auch der Client denselben JS-Code ausführen.

.

Das Problem insgesamt umgehen: Hash-Verlauf

Mit Hash History anstelle von Browser History würde Ihre URL für die About-Seite ungefähr so ​​aussehen: http://example.com/#/about Der Teil nach dem Hash (#) Symbol wird nicht an den Server gesendet. Der Server sieht also nur http://example.com/ Und sendet die Indexseite wie erwartet. React-Router hebt den Teil #/about Auf und zeigt die richtige Seite an.

Nachteile :

  • "hässliche" URLs
  • Server-seitiges Rendern ist mit diesem Ansatz nicht möglich. Für die Suchmaschinenoptimierung (SEO) besteht Ihre Website aus einer einzigen Seite, auf der sich kaum Inhalte befinden.

.

Alles in allem

Bei diesem Ansatz verwenden Sie den Browserverlauf, richten jedoch auf dem Server einen Sammelpunkt ein, der /* An index.html Sendet, sodass Sie praktisch die gleiche Situation wie beim Hash-Verlauf haben. Sie haben jedoch saubere URLs und können dieses Schema später verbessern, ohne alle Favoriten Ihres Benutzers ungültig machen zu müssen.

Nachteile :

  • Komplexer einzurichten
  • Immer noch keine gute SEO

.

Hybrid

Im Hybridansatz erweitern Sie das Catch-All-Szenario, indem Sie bestimmte Skripte für bestimmte Routen hinzufügen. Sie könnten einige einfache PHP Skripte erstellen, um die wichtigsten Seiten Ihrer Website mit eingeschlossenem Inhalt zurückzugeben, damit Googlebot zumindest sehen kann, was auf Ihrer Seite ist.

Nachteile :

  • Noch komplexer einzurichten
  • Nur eine gute Suchmaschinenoptimierung für diese Routen gibt Ihnen die Sonderbehandlung
  • Duplizieren von Code zum Rendern von Inhalten auf Server und Client

.

Isomorph

Was ist, wenn wir Node JS als Server verwenden, damit wir den gleichen JS-Code auf beiden Seiten ausführen können? Jetzt haben wir alle unsere Routen in einer einzigen Reaktion-Router-Konfiguration definiert und müssen unseren Rendering-Code nicht duplizieren. Das ist sozusagen der heilige Gral. Der Server sendet genau das Markup, das wir erhalten würden, wenn der Seitenübergang auf dem Client stattgefunden hätte. Diese Lösung ist in Bezug auf SEO optimal.

Nachteile :

  • Server muss (kann) JS ausführen. Ich habe mit Java i.c.w experimentiert. Nashorn, aber es funktioniert nicht für mich. In der Praxis bedeutet dies meistens, dass Sie einen Node JS-basierten Server verwenden müssen.
  • Viele knifflige Umweltprobleme (Verwendung von window auf dem Server usw.)
  • Steile Lernkurve

.

Welches soll ich verwenden?

Wählen Sie die, mit der Sie durchkommen können. Persönlich denke ich, dass das Auffangen einfach genug ist, um es einzurichten, also wäre das mein Minimum. Mit diesem Setup können Sie die Dinge im Laufe der Zeit verbessern. Wenn Sie bereits Node JS als Serverplattform verwenden, würde ich auf jeden Fall eine isomorphe App untersuchen. Ja, es ist anfangs schwierig, aber sobald Sie den Dreh raus haben, ist es eine sehr elegante Lösung für das Problem.

Für mich wäre das also der entscheidende Faktor. Wenn mein Server auf Node JS läuft, würde ich isomorph werden. Andernfalls würde ich mich für die Catch-all-Lösung entscheiden und sie einfach erweitern (Hybrid-Lösung), wenn die Zeit fortschreitet und die SEO-Anforderungen dies erfordern.

Wenn Sie mehr über isomorphes Rendern (auch als "universelles" Rendern bezeichnet) mit React erfahren möchten, finden Sie einige gute Tutorials zu diesem Thema:

Um Ihnen den Einstieg zu erleichtern, empfehle ich Ihnen, sich einige Starterkits anzusehen. Wählen Sie eine aus, die Ihren Auswahlmöglichkeiten für den Technologie-Stack entspricht (denken Sie daran, dass React nur das V in MVC ist, Sie benötigen mehr Dinge, um eine vollständige App zu erstellen). Beginnen Sie mit dem von Facebook selbst veröffentlichten:

Oder wählen Sie eine der vielen von der Gemeinde. Es gibt jetzt eine nette Seite, die versucht, alle zu indizieren:

Ich begann mit diesen:

Momentan verwende ich eine selbstgebraute Version des Universal-Renderings, die von den beiden oben genannten Starter-Kits inspiriert wurde, aber jetzt veraltet ist.

Viel Glück bei deiner Suche!

845
Stijn de Witt

Die Antworten hier sind alle sehr hilfreich. Für mich war das Konfigurieren meines Webpack-Servers so, dass er die Routen erwartet.

  devServer: {
    historyApiFallback: true,
    contentBase: './',
    hot: true
  },

Der historyApiFallback hat dieses Problem für mich behoben. Das Routing funktioniert nun korrekt und ich kann die Seite aktualisieren oder die URL direkt eingeben. Sie müssen sich keine Sorgen um die Umgehung Ihres Knotenservers machen. Diese Antwort funktioniert natürlich nur, wenn Sie Webpack verwenden.

BEARBEITEN: Siehe meine Antwort hier für einen detaillierteren Grund, warum dies notwendig ist: https://stackoverflow.com/a/37622953/5217568

84
jmancherje

Für React Router V4 Benutzer:

Wenn Sie versuchen, dieses Problem durch die in anderen Antworten erwähnte Hash History-Technik zu lösen, beachten Sie das 

<Router history={hashHistory} >

funktioniert nicht in V4, verwenden Sie stattdessen HashRouter:

import { HashRouter } from 'react-router-dom'

<HashRouter>
  <App/>
</HashRouter>

Referenz: https://reacttraining.com/react-router/web/api/HashRouter

38
user2875289

Sie können Ihren Zugriff ändern und Folgendes einfügen:

RewriteBase /
RewriteRule ^index\.html$ - [L]
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]

Ich verwende react: "^15.3.2", react-router: "^3.0.0", history: "^4.3.0",

38
BrahimS

Der Router kann auf zwei verschiedene Arten aufgerufen werden, je nachdem, ob die Navigation auf dem Client oder auf dem Server erfolgt. Sie haben es für den clientseitigen Betrieb konfiguriert. Der Schlüsselparameter ist der zweite der run-Methode , der Position.

Wenn Sie die React Router Link-Komponente verwenden, blockiert sie die Browsernavigation und ruft Übergangsto auf, um eine clientseitige Navigation durchzuführen. Da Sie HistoryLocation verwenden, verwendet es die HTML5-Verlaufs-API, um die Illusion der Navigation abzuschließen, indem Sie die neue URL in der Adressleiste simulieren. Wenn Sie ältere Browser verwenden, funktioniert dies nicht. Sie müssten die HashLocation-Komponente verwenden.

Wenn Sie auf "Aktualisieren" klicken, umgehen Sie den gesamten React- und React-Router-Code. Der Server erhält die Anforderung für /joblist und muss etwas zurückgeben. Auf dem Server müssen Sie den angeforderten Pfad an die run-Methode übergeben, damit die korrekte Ansicht angezeigt wird. Sie können dieselbe Routenkarte verwenden, aber wahrscheinlich benötigen Sie einen anderen Aufruf von Router.run. Wie Charles darauf hinweist, können Sie das URL-Umschreiben verwenden. Eine andere Option besteht darin, einen node.js-Server zu verwenden, um alle Anforderungen zu verarbeiten und den Pfadwert als Standortargument zu übergeben. 

Zum Beispiel könnte es so aussehen:

var app = express();

app.get('*', function (req, res) { // This wildcard method handles all requests

    Router.run(routes, req.path, function (Handler, state) {
        var element = React.createElement(Handler);
        var html = React.renderToString(element);
        res.render('main', { content: html });
    });
});

Beachten Sie, dass der Anforderungspfad an run übergeben wird. Dazu benötigen Sie eine serverseitige View-Engine, an die Sie den gerenderten HTML-Code übergeben können. Bei der Verwendung von renderToString und beim Ausführen von React auf dem Server gibt es eine Reihe weiterer Überlegungen. Sobald die Seite auf dem Server gerendert ist und Ihre App im Client geladen wird, wird sie erneut gerendert, und der serverseitig gerenderte HTML-Code wird bei Bedarf aktualisiert.

25
Todd

Fügen Sie in Ihrer index.html head Folgendes hinzu:

<base href="/">
<!-- This must come before the css and javascripts -->

Verwenden Sie dann diesen Befehl, wenn Sie mit dem webpack dev-Server laufen.

webpack-dev-server --mode development --hot --inline --content-base=dist --history-api-fallback

--history-api-fallback ist der wichtige Teil

16
Efe Ariaroo

Der Webpack Dev Server verfügt über eine Option, um dies zu aktivieren. Öffnen Sie package.json und fügen Sie --history-api-fallback..__ hinzu. Diese Lösungen haben für mich funktioniert.

https://github.com/reactjs/react-router-tutorial/tree/master/lessons/10-clean-urls#configuring-your-server

14
srijishks

Wenn Sie eine Reaktions-App über AWS Static S3 Hosting & CloudFront hosten

Dieses Problem trat auf, als CloudFront mit einer 403-Meldung "Zugriff verweigert" antwortete, da in meinem S3-Ordner der Pfad "/ some/other /" erwartet wurde. Dieser Pfad ist jedoch nur intern im React-Routing mit dem reaktiven Router vorhanden. 

Die Lösung bestand darin, eine Verteilungsfehlerseitenregel einzurichten. Gehen Sie zu den CloudFront-Einstellungen und wählen Sie Ihre Verteilung aus. Gehen Sie dann zur Registerkarte "Fehlerseiten". Klicken Sie auf "Create Custom Error Response" und fügen Sie einen Eintrag für 403 hinzu, da dies der Fehlerstatuscode ist, den wir erhalten. Setzen Sie den Antwortseitenpfad auf /index.html und den Statuscode auf 200. Das Endergebnis überrascht mit seiner Einfachheit. Die Indexseite wird bereitgestellt, aber die URL wird im Browser beibehalten. Sobald die React-App geladen wird, erkennt sie den URL-Pfad und navigiert zur gewünschten Route. 

Fehlerseiten-403-Regel

11
th3morg

Dies kann Ihr Problem lösen 

Das gleiche Problem hatte ich auch in der ReactJS-Anwendung im Produktionsmodus. Hier ist die 2 Lösung für das Problem.

1. Ändern Sie den Routing-Verlauf anstelle von browserHistory in "hashHistory" 

 <Router history={hashHistory} >
   <Route path="/home" component={Home} />
   <Route path="/aboutus" component={AboutUs} />
 </Router>

Erstellen Sie nun die App mit dem Befehl 

Sudo npm run build

Legen Sie dann den Build-Ordner in Ihren var/www/-Ordner. Nun funktioniert die Anwendung mit dem Hinzufügen des # -Tags in jeder einzelnen URL. mögen 

localhost/#/home localhost/#/aboutus

Lösung 2: Ohne # tag mit browserHistory,

Legen Sie in Ihrem Router Ihr history = {browserHistory} fest. Erstellen Sie es jetzt mit Sudo npm run build.

Sie müssen die "conf" -Datei erstellen, um die nicht gefundene 404-Seite zu lösen. Die -Datei sollte so aussehen.

Öffnen Sie Ihr Terminal mit den folgenden Befehlen 

cd /etc/Apache2/sites-availablelsnano sample.conf Fügen Sie den folgenden Inhalt hinzu.

 <VirtualHost *:80>
    ServerAdmin [email protected]
    ServerName 0.0.0.0
    ServerAlias 0.0.0.0
    DocumentRoot /var/www/html/

    ErrorLog ${Apache_LOG_DIR}/error.log
    CustomLog ${Apache_LOG_DIR}/access.log combined
    <Directory "/var/www/html/">
            Options Indexes FollowSymLinks
            AllowOverride all
            Require all granted
    </Directory>
</VirtualHost>

Jetzt müssen Sie die Datei sample.conf mit dem folgenden Befehl aktivieren

cd /etc/Apache2/sites-available
Sudo a2ensite sample.conf

anschließend werden Sie aufgefordert, den Apache-Server mithilfe von .__ neu zu laden. Sudo-Dienst Apache2 neu laden oder neu starten

Öffnen Sie dann den Ordner localhost/build und fügen Sie die .htaccess-Datei mit dem folgenden Inhalt hinzu.

   RewriteEngine On
   RewriteBase /
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteCond %{REQUEST_FILENAME} !-d
   RewriteCond %{REQUEST_FILENAME} !-l
   RewriteRule ^.*$ / [L,QSA]

Jetzt funktioniert die App normal.

Hinweis: Ändern Sie 0.0.0.0 in Ihre lokale IP-Adresse.

Wenn Sie diesbezüglich Zweifel haben, können Sie sich gerne dazu äußern.

Ich hoffe es ist hilfreich für andere.

11
Venkatesh Somu

Ich habe gerade erst mit create -react-app eine Website erstellt und hatte das gleiche Problem hier. Ich verwende BrowserRouting aus dem react-router-dom-Paket. Ich arbeite auf einem Nginx-Server und löste Folgendes für /etc/nginx/yourconfig.conf:

location / {
  if (!-e $request_filename){
    rewrite ^(.*)$ /index.html break;
  }
}

Dies entspricht dem Hinzufügen des folgenden Codes zum .htaccess, falls Sie Appache ausführen

Options -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.html [QSA,L]

Dies scheint auch die Lösung zu sein, die von Facebook selbst vorgeschlagen wurde und ist hier zu finden.

10
Aidin

fügen Sie dies zu webpack.config.js hinzu

devServer: {
      historyApiFallback: true
  }
8
suraj

Produktionsstapel: React, React Router v4, BrowswerRouter, Express, Nginx

1) User BrowserRouter für hübsche URLs 

// app.js

import { BrowserRouter as Router } from 'react-router-dom'

const App = () {
  render() {
    return (
        <Router>
           // your routes here
        </Router>
    )
  }
}

2) Fügen Sie allen unbekannten Anforderungen index.html hinzu, indem Sie /* verwenden.

// server.js

app.get('/*', function(req, res) {   
  res.sendFile(path.join(__dirname, 'path/to/your/index.html'), function(err) {
    if (err) {
      res.status(500).send(err)
    }
  })
})

3) Webpack mit webpack -p bündeln

4) nodemon server.js oder node server.js ausführen

BEARBEITEN: Möglicherweise möchten Sie, dass Nginx dies im Serverblock ausführt, und ignoriert Schritt 2:

location / {
    try_files $uri /index.html;
}
7
Isaac Pak

Versuchen Sie, die Datei ".htaccess" im öffentlichen Ordner mit dem folgenden Code hinzuzufügen.

RewriteEngine On
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]

RewriteRule ^ /index.html [L]  
6
Kiran Joshi

Wenn Sie Create React App verwenden:

Es gibt jedoch einen großartigen Spaziergang dieses Problems mit Lösungen für viele wichtige Hosting-Plattformen, die Sie HERE auf der Seite React App erstellen finden. Beispielsweise verwende ich für meinen Frontend-Code React Router v4 und Netlify. Alles, was Sie dafür brauchten, war das Hinzufügen einer Datei zu meinem öffentlichen Ordner ("_redirects") und einer Codezeile in dieser Datei:

/*  /index.html  200

Jetzt stellt meine Website Pfade wie mysite.com/pricing korrekt dar, wenn sie in den Browser eingegeben werden oder wenn jemand auf "Aktualisieren" klickt.

4
Colton Hicks

Wenn Sie einen Rückfall auf Ihre index.html haben, stellen Sie sicher, dass Sie in Ihrer index.html-Datei Folgendes haben:

<script>
  System.config({ baseURL: '/' });
</script>

Dies kann von Projekt zu Projekt unterschiedlich sein.

2
Matt Goo

Wenn Sie Ihre Reakt-App auf IIS hosten, fügen Sie einfach eine Datei web.config hinzu, die Folgendes enthält:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <httpErrors errorMode="Custom" existingResponse="Replace">
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" path="/" responseMode="ExecuteURL" />
    </httpErrors>
  </system.webServer>
</configuration>

Dies weist den IIS -Server an, die Hauptseite anstelle des 404-Fehlers an den Client zurückzugeben und keine Hash-Historie zu verwenden.

2
Chtiwi Malek

Ich verwende zwar noch kein serverseitiges Rendering, aber ich hatte das gleiche Problem wie das OP, bei dem Link die meiste Zeit einwandfrei zu funktionieren schien, aber fehlschlug, wenn ich einen Parameter hatte. Ich werde meine Lösung hier dokumentieren, um zu sehen, ob sie jemandem hilft.

Mein Haupt-Jsx enthält folgendes:

<Route onEnter={requireLogin} path="detail/:id" component={ModelDetail} />

Dies funktioniert gut für den ersten übereinstimmenden Link. Wenn sich jedoch die: id in <Link>-Ausdrücken ändert, die auf der Detailseite dieses Modells verschachtelt sind, ändert sich die URL in der Browserleiste. Der Inhalt der Seite wurde jedoch anfangs nicht entsprechend dem verknüpften Modell geändert.

Das Problem war, dass ich den props.params.id verwendet hatte, um das Modell in componentDidMount zu setzen. Die Komponente wird nur einmal montiert. Dies bedeutet, dass das erste Modell dasjenige ist, das auf der Seite klebt. Die nachfolgenden Links ändern die Requisiten, lassen die Seite jedoch unverändert.

Wenn Sie das Modell sowohl in componentDidMount als auch in componentWillReceiveProps (wo es auf den nächsten Requisiten basiert) in den Komponentenzustand setzen, wird das Problem gelöst, und der Seiteninhalt ändert sich entsprechend dem gewünschten Modell.

2
Paul Whipp

Dieses Thema ist ein bisschen alt und gelöst, aber ich möchte Ihnen eine einfache, klare und bessere Lösung vorschlagen. Es funktioniert, wenn Sie einen Webserver verwenden.

Jeder Webserver kann den Benutzer bei http 404 auf eine Fehlerseite umleiten. Um dieses Problem zu beheben, müssen Sie den Benutzer zur Indexseite umleiten.

Wenn Sie einen Java-Basisserver (Tomcat oder einen beliebigen Java-Anwendungsserver) verwenden, kann dies folgende Lösung sein:

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <!-- WELCOME FILE LIST -->
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <!-- ERROR PAGES DEFINITION -->
    <error-page>
        <error-code>404</error-code>
        <location>/index.jsp</location>
    </error-page>

</web-app>

Beispiel:

  • GET http://example.com/about
  • Webserver gibt http 404 aus, da diese Seite auf der Serverseite nicht vorhanden ist
  • die Fehlerseitenkonfiguration teilt dem Server mit, der die Seite index.jsp an den Benutzer zurücksendet
  • dann erledigt JS den Rest des Jobs auf der Clienseite, da die URL auf der Clientseite immer noch http://example.com/about ist.

Das ist es, keine magischen Bedürfnisse mehr :)

2
zappee

Da ich .Net Core MVC verwende, hat mir Folgendes geholfen:

    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            var url = Request.Path + Request.QueryString;
            return App(url);
        }

        [Route("App")]
        public IActionResult App(string url)
        {
            return View("/wwwroot/app/build/index.html");
        }
   }

Grundsätzlich werden auf der MVC-Seite alle nicht übereinstimmenden Routen zu Home/Index, wie in startup.cs angegeben. Innerhalb von Index ist es möglich, die ursprüngliche Anforderungs-URL abzurufen und sie zu übergeben, wo immer sie benötigt wird.

startup.cs

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");

            routes.MapSpaFallbackRoute(
                name: "spa-fallback",
                defaults: new { controller = "Home", action = "Index" });
        });
1
Elnoor

Falls jemand hier mit Laravel nach einer Lösung für React JS SPA sucht. Die akzeptierte Antwort ist die beste Erklärung dafür, warum solche Probleme auftreten. Wie bereits erläutert, müssen Sie sowohl die Client- als auch die Serverseite konfigurieren. __ Fügen Sie in Ihre Blade-Vorlage die js-gebündelte Datei ein, und verwenden Sie URL facade wie folgt

<script src="{{ URL::to('js/user/spa.js') }}"></script>

Fügen Sie dies in Ihren Routen dem Hauptendpunkt hinzu, an dem sich die Blade-Vorlage befindet. Zum Beispiel,

Route::get('/setting-alerts', function () {
   return view('user.set-alerts');
});

Das Obige ist der Hauptendpunkt für die Blade-Vorlage. Fügen Sie jetzt eine optionale Route hinzu.

Route::get('/setting-alerts/{spa?}', function () {
  return view('user.set-alerts');
});

Das Problem ist, dass zuerst die Blade-Vorlage geladen wird und dann der Reaktiver Router. Wenn Sie also '/setting-alerts' laden, werden HTML und JS geladen. Wenn Sie jedoch '/setting-alerts/about' laden, wird es zuerst auf der Serverseite geladen. Da es auf der Serverseite nichts an dieser Position gibt, wird es nicht gefunden zurückgegeben. Wenn Sie diesen optionalen Router haben, lädt er dieselbe Seite, und der Reaktorrouter wird ebenfalls geladen. Der Loader entscheidet dann, welche Komponente angezeigt werden soll . Hoffe, das hilft.

1
Koushik Das

Wenn Sie Express oder ein anderes Framework im Backend verwenden, können Sie die ähnliche Konfiguration wie unten hinzufügen und den öffentlichen Webpack-Pfad in der Konfiguration auschecken. Wenn Sie BrowserRouter verwenden, sollte dies auch beim Neuladen problemlos funktionieren

` expressApp.get('/*', (request, response) => {
    response.sendFile(path.join(__dirname, '../public/index.html'));
  });`
1
user2849063

Hinzufügen weiterer Informationen zu Joshua Dycks Antwort .

Wenn Sie Firebase verwenden und sowohl die Root-Route als auch eine Unterverzeichnis-Route verwenden möchten, müssen Sie den folgenden Code in Ihren firebase.json einfügen:

{
  "hosting": {
    "rewrites": [
      {
        "source": "*",
        "destination": "/index.html"
      },
      {
        "source": "/subdirectory/**",
        "destination": "/subdirectory/index.html"
      }
    ]
  }
}

Beispiel:

Sie erstellen eine Website für einen Kunden. Sie möchten, dass der Eigentümer der Website Informationen in https://ihre.domain.com/management hinzufügt, während die Benutzer der Website zu https://ihre.domain.com navigieren.

In diesem Fall sieht Ihre firebase.json-Datei folgendermaßen aus:

{
  "hosting": {
    "rewrites": [
      {
        "source": "*",
        "destination": "/index.html"
      },
      {
        "source": "/management/**",
        "destination": "/management/index.html"
      }
    ]
  }
}
0
neomib

Hier ist eine Frontend-Problemumgehung, die keine Änderungen auf dem Server erfordert.

Angenommen, Ihre Website ist mysite.com und Sie haben eine React Route zu mysite.com/about. In index.js, wo Sie Ihre Top-Level-Komponente einbinden, können Sie einen anderen Router wie folgt einfügen:

ReactDOM.render(
<Router>
    <div>
        <Route exact path="/" component={Home} />
        <Route exact path="/about"
            render={(props) => <Home {...props} refreshRout={"/about"}/>}
        />
    </div>
</Router>,

Ich gehe davon aus, dass Sie den ursprünglichen Router irgendwo unterhalb der obersten Komponente im virtuellen DOM haben. Sie müssen die URL auch in Ihren .urls abfangen, wenn Sie Django verwenden, wie:

urlpatterns = [
       path('about/', views.index),
]

Dies hängt jedoch davon ab, welches Backend Sie verwenden. Wenn Sie mysite/about anfordern, gelangen Sie zu index.js (wo Sie die Komponente der obersten Ebene einbinden), wo Sie die Renderstütze der Route anstelle der Komponentenstütze verwenden und '/ about' als Stütze an übergeben können In diesem Beispiel die Home-Komponente.

Führen Sie in Home entweder in componentDidMount () oder in useEffect () Folgendes aus:

useEffect() {   
   //check that this.props.refreshRoute actually exists before executing the 
   //following line    
   this.props.history.replace(this.props.refreshRoute);
}

Ich bin davon ausgegangen, dass Ihre Home-Komponente so etwas wie Folgendes wiedergibt:

<Router>
   <Route exact path="/" component={SomeComponent} />
   <Route path="/about" component={AboutComponent} />
</Router>

Gutschrift für ( Requisiten an eine von React Router gerenderte Komponente übergeben ) für das Übergeben von Requisiten an Komponenten in Routes.

0
Stevie

Vollständige Router mit Beispiel (React Router v4):

Arbeitsbeispiel Beispiel Schauen Sie sich das Projekt unten an.

https://github.com/eh3rrera/react-router-4-example

Nach dem Download 
1.) "Npm install" in cmd, um das Projekt zu installieren 
2.) "Npm start", um Ihre Reakt-App zu starten

Hinweis: Sie benötigen Node js-Software, um unter Ihren Fenstern zu laufen. Mac OS haben Knotenstandard. 

Prost

0
Muthu Kumar

Für diejenigen, die IIS 10 verwenden, sollten Sie dies tun, um dies richtig zu machen. Stellen Sie sicher, dass Sie browserHistory damit verwenden. Als Referenz gebe ich den Code für das Routing an, aber es kommt nicht darauf an, sondern auf den nächsten Schritt nach dem folgenden Komponentencode:

class App extends Component {
    render() {
        return (
            <Router history={browserHistory}>
                <div>
                    <Root>
                        <Switch>
                            <Route exact path={"/"} component={Home} />    
                            <Route path={"/home"} component={Home} />
                            <Route path={"/createnewproject"} component={CreateNewProject} />
                            <Route path={"/projects"} component={Projects} />
                            <Route path="*" component={NotFoundRoute} />
                        </Switch>
                    </Root>
                </div>
            </Router>
        )
    }
}
render (<App />, window.document.getElementById("app"));

Da das Problem darin besteht, dass IIS eine Anforderung von Client-Browsern empfängt, interpretiert es die URL so, als würde sie nach einer Seite fragen, und gibt dann eine 404-Seite zurück, da keine verfügbare Seite vorhanden ist. Mach Folgendes:

  1. Öffnen Sie IIS
  2. Erweitern Sie Server, und öffnen Sie den Ordner "Sites"
  3. Klicken Sie auf die Website/Anwendung
  4. Gehen Sie zu den Fehlerseiten
  5. Öffnen Sie den 404-Fehlerstatus in der Liste
  6. Ändern Sie statt der Option "Inhalt aus statischer Datei in die Fehlerantwort einfügen" in "URL auf dieser Site ausführen" und fügen Sie der URL einen Schrägstrich "/" hinzu.

Und es wird jetzt gut funktionieren.

 enter image description here  enter image description here

Ich hoffe, es hilft. :-)

0

Ich verwende WebPack, ich hatte das gleiche Problem Lösung => In Ihrer server.js-Datei

const express = require('express');
const app = express();

app.use(express.static(path.resolve(__dirname, '../dist')));
  app.get('*', function (req, res) {
    res.sendFile(path.resolve(__dirname, '../dist/index.html'));
    // res.end();
  });

https://github.com/ReactTraining/react-router/blob/master/FAQ.md#why-doesnt-my-application-render-after-refreshing

0
Vishal Singh

Wenn Sie in IIS hosten; Das Hinzufügen zu meinem webconfig löste mein Problem

    <httpErrors errorMode="Custom" defaultResponseMode="ExecuteURL">
        <remove statusCode="500" subStatusCode="100" />
        <remove statusCode="500" subStatusCode="-1" />
        <remove statusCode="404" subStatusCode="-1" />
        <error statusCode="404" path="/" responseMode="ExecuteURL" />
        <error statusCode="500" prefixLanguageFilePath="" path="/error_500.asp" responseMode="ExecuteURL" />
        <error statusCode="500" subStatusCode="100" path="/error_500.asp" responseMode="ExecuteURL" />
    </httpErrors>

Sie können eine ähnliche Konfiguration für jeden anderen Server vornehmen

0
Barny

Angenommen, Sie haben die folgende Definition der Home-Route

<Route exact path="/" render={routeProps => (
   <Home routeProps={routeProps}/>
)}/>

{/*optional catch-all router */}
<Route render={routeProps => (
       <div><h4>404 not found</h4></div>
)}/>

An Ihrer Home-Komponente können Sie die Anforderung beim ComponentWillMount-Ereignis abfangen.

const searchPath = this.props.routeProps.location.search;

if (searchPath){
    this.props.routeProps.history.Push("/" + searchPath.replace("?",""));
}
else{
    /*.... originally Home event */
}

Anstatt jetzt/joblist unter url aufzurufen, können Sie /? Joblist anfordern, und die Komponente leitet die Anforderung automatisch an/joblist um (beachten Sie das zusätzliche Fragezeichen im Pfad).

0
user2674595

Wenn Sie hierher kommen und Apache verwenden und keine .htaccess-Datei haben, ist dies eine Konfigurationsdatei, die für mich funktioniert hat:

sites-enabled/somedomain.com.conf

<VirtualHost *:80>
    ServerName somedomain.com
    ServerAlias *.somedomain.com
    DocumentRoot /www/somedomain.com/build

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /www/somedomain.com/build/index.html [L,NC,QSA]

</VirtualHost>
0
DevB2F

Ich hatte das gleiche Problem und diese Lösung funktionierte für uns ..

Hintergrund:

Wir hosten mehrere Apps auf demselben Server. Wenn wir den Server aktualisieren würden, würde er nicht verstehen, wo er im dist-Ordner für diese bestimmte App nach unserem Index suchen soll. Der obige Link führt Sie zu dem, was für uns funktioniert hat ... Hoffe, das hilft, denn wir haben eine ganze Stunde damit verbracht, eine Lösung für unsere Bedürfnisse zu finden. 

Wir benutzen:

package.json

"dependencies": {
"babel-polyfill": "^6.23.0",
"ejs": "^2.5.6",
"express": "^4.15.2",
"prop-types": "^15.5.6",
"react": "^15.5.4",
"react-dom": "^15.5.4",
"react-redux": "^5.0.4",
"react-router": "^3.0.2",
"react-router-redux": "^4.0.8",
"redux": "^3.6.0",
"redux-persist": "^4.6.0",
"redux-thunk": "^2.2.0",
"webpack": "^2.4.1"
}

meine webpack.config.js

webpack.config.js

/* eslint-disable */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const babelPolyfill = require('babel-polyfill');
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: __dirname + '/app/views/index.html',
  filename: 'index.html',
  inject: 'body'
});

module.exports = {
  entry: [
    'babel-polyfill', './app/index.js'
  ],
  output: {
    path: __dirname + '/dist/your_app_name_here',
    filename: 'index_bundle.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      loader: 'babel-loader',
      query : {
          presets : ["env", "react", "stage-1"]
      },
      exclude: /node_modules/
    }]
  },
  plugins: [HTMLWebpackPluginConfig]
}

meine index.js

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import Routes from './Routes'
import { Provider } from 'react-redux'
import { createHistory } from 'history'
import { useRouterHistory } from 'react-router'
import configureStore from './store/configureStore'
import { syncHistoryWithStore } from 'react-router-redux'
import { persistStore } from 'redux-persist'

const store = configureStore();

const browserHistory = useRouterHistory(createHistory) ({
  basename: '/your_app_name_here'
})
const history = syncHistoryWithStore(browserHistory, store)

persistStore(store, {blacklist: ['routing']}, () => {
  console.log('rehydration complete')
})
// persistStore(store).purge()


ReactDOM.render(
    <Provider store={store}>
      <div>
        <Routes history={history} />
      </div>
    </Provider>,
  document.getElementById('mount')
)

meine app.js

var express = require('express');
var app = express();

app.use(express.static(__dirname + '/dist'));
// app.use(express.static(__dirname + '/app/assets'));
app.set('views', __dirname + '/dist/your_app_name_here');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');

app.get('/*', function (req, res) {
    res.render('index');
});

app.listen(8081, function () {
  console.log('MD listening on port 8081!');
});
0
J. Parrish

Behebung des Fehlers "Keine GET/URL" bei Aktualisierung oder direktem Aufruf der URL.

Konfigurieren Sie Ihrewebpack.config.js, um zu erwarten, dass der angegebene Link den Routen wie folgt entspricht.

module.exports = {
  entry: './app/index.js',
  output: {
       path: path.join(__dirname, '/bundle'),
       filename: 'index_bundle.js',
       publicPath: '/'
    },
0
Lalit Tyagi

Ich mag diesen Umgang damit. Fügen Sie auf der Serverseite Folgendes hinzu: yourSPAPageRoute/*, um dieses Problem zu beheben. 

Ich habe diesen Ansatz gewählt, weil selbst die native HTML5-Verlaufs-API keine korrekte Umleitung bei der Seitenaktualisierung unterstützt (soweit ich weiß).

Hinweis: Die ausgewählte Antwort hat dieses Problem bereits angesprochen, aber ich versuche, genauer zu sein.

Express Route

 Test - History API Getestet und wollte das nur teilen.

Ich hoffe es hilft.

0
Rehan

Lösung für Preact mit Preact-Router

Funktioniert mit Aktualisierung und direktem Zugriff

Für diejenigen, die dies über Google erfahren, ist hier eine Demo der Preact-Router + Hash-Geschichte:

const { h, Component, render } = preact; /** @jsx h */
const { Router } = preactRouter;
const { createHashHistory } = History;
const App = () => (
    <div>
        <AddressBar />

        <Router history={createHashHistory()}>
            <div path="/">
                <p>
                    all paths in preact-router are still /normal/urls.
                    using hash history rewrites them to /#/hash/urls
                </p>
                Example: <a href="/page2">page 2</a>
            </div>
            <div path="/page2">
                <p>Page Two</p>
                <a href="/">back to home</a><br/>
            </div>
        </Router>
    </div>
);

https://jsfiddle.net/developit/gLyL6rbn/

0
keemor

Ich habe die Lösung für meinen SPA mit Reaktiver Router (Apache) gefunden. Fügen Sie einfach .htaccess hinzu

<IfModule mod_rewrite.c>

  RewriteEngine On
  RewriteBase /
  RewriteRule ^index\.html$ - [L]
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-l
  RewriteRule . /index.html [L]

</IfModule>

source: https://Gist.github.com/alexsasharegan/173878f9d67055bfef63449fa7136042

0

Wenn Sie Firebase verwenden, müssen Sie lediglich sicherstellen, dass in der Datei firebase.json im Stammverzeichnis Ihrer App (im Hosting-Bereich) eine Eigenschaft zum Umschreiben vorhanden ist. 

Zum Beispiel:

{ 
  "hosting": {
    "rewrites": [{
      "source":"**",
      "destination": "/index.html"
    }]    
  }
}

Ich hoffe, das erspart jemand anderem einen Haufen Frustration und Zeitverschwendung.

Viel Spaß beim Kodieren ...

Weitere Lektüre zum Thema:

https://firebase.google.com/docs/hosting/full-config#rewrites

Firebase-CLI: "Als einseitige App konfigurieren (alle URLs in /index.html schreiben)"

0
Joshua Dyck

Es ist ziemlich einfach, wenn Sie erhalten 403 Fehler nach Aktualisierung Dom Komponente nicht erhalten. Fügen Sie einfach diese Zeile in Ihre Web Pack-Konfiguration ein: 'historyApiFallback: true'. das rettet meinen ganzen Tag.

0
praveenkumar s