React-Router v4 - kann * url * nicht abrufen

74

Ich fing an, React-Router v4 zu verwenden. Ich habe eine einfache <Router>in meiner app.js mit einigen Navigationslinks (siehe Code unten). Wenn ich zu navigiere localhost/vocabulary, leitet mich der Router auf die richtige Seite weiter. Wenn ich jedoch anschließend ( localhost/vocabulary) neu laden (F5) drücke , verschwinden alle Inhalte und der Browser meldet sich Cannot GET /vocabulary. Wie ist das möglich? Kann mir jemand einen Hinweis geben, wie ich das lösen kann (die Seite richtig laden)?

App.js:

import React from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'
import { Switch, Redirect } from 'react-router'
import Login from './pages/Login'
import Vocabulary from './pages/Vocabulary'

const appContainer = document.getElementById('app')

ReactDOM.render(
  <Router>
    <div>
        <ul>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/vocabulary">Vocabulary</Link></li>
        </ul>
        <Switch>
          <Route exact path="/" component={Login} />
          <Route exact path="/vocabulary" component={Vocabulary} />
        </Switch>
    </div>
  </Router>,
appContainer)
exoslawisch
quelle

Antworten:

215

Ich gehe davon aus, dass Sie Webpack verwenden. Wenn ja, sollte das Problem durch Hinzufügen einiger Dinge zu Ihrer Webpack-Konfiguration behoben werden. Insbesondere output.publicPath = '/'und devServer.historyApiFallback = true. Hier ist ein Beispiel für eine Webpack-Konfiguration, die beide von ^ verwendet und das Aktualisierungsproblem für mich behebt. Wenn Sie neugierig : „Warum“, dies wird dazu beitragen.

var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './app/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'index_bundle.js',
    publicPath: '/'
  },
  module: {
    rules: [
      { test: /\.(js)$/, use: 'babel-loader' },
      { test: /\.css$/, use: [ 'style-loader', 'css-loader' ]}
    ]
  },
  devServer: {
    historyApiFallback: true,
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'app/index.html'
    })
  ]
};

Ich habe hier mehr darüber geschrieben - Behebung des Fehlers "Kann nicht erhalten / URL" beim Aktualisieren mit React Router (oder wie clientseitige Router funktionieren)

Tyler McGinnis
quelle
17
bearbeitet von hinzugefügt devServer: {historyApiFallback: true,},
SKLTFZ
Verwenden Sie HtmlWebpackPlugin nicht mit index.html als Vorlage, da das Bundle beim Aktualisieren einer Route nicht eingefügt wird. Fügen Sie das Skript bundle.js direkt als Skript-Tag in die Datei index.html ein.
Peterorum
3
Es funktionierte für mich nur das Hinzufügen, das devServer { historyApiFallback: true } ich bereits publicPath: '/'konfiguriert hatte
Andre Evangelista
Vielen Dank! In vielen Quellen sagen alle, dass sie historyApiFallback hinzufügen, aber sie hatten nie über output.publicPath = '/' gesprochen. Ich habe meinen publicPath nicht konfiguriert, sodass ich mein Problem erst lösen konnte, wenn ich Ihren Beitrag gesehen habe.
Nezih
1
+1 von mir und vergessen Sie nicht, den Server jedes Mal neu zu starten (wenn Sie Hotload aktiviert haben), wenn Sie webpack.config.js ändern.
BlondCode
15

Nur um Tylers Antwort für alle zu ergänzen, die immer noch damit zu kämpfen haben:

Durch Hinzufügen der devServer.historyApiFallback: truezu meiner Webpack-Konfiguration (ohne Einstellung publicPath) wurden die 404 / Cannot-GET-Fehler behoben, die beim Aktualisieren / Zurück / Vorwärts angezeigt wurden , jedoch nur für eine einzelne Ebene verschachtelter Routen. Mit anderen Worten, "/" und "/ topic" funktionierten einwandfrei, aber alles darüber hinaus (z. B. "/ topic / Whatever") warf immer noch einen 404 auf refresh / etc.

Ich bin gerade auf die akzeptierte Antwort hier gestoßen : Unerwartetes Token <Fehler in der React Router-Komponente und es war das letzte fehlende Teil für mich. Das Hinzufügen des führenden /zum Bundle-Skript src in my index.htmlhat das Problem vollständig gelöst.

Will Ashe
quelle
5

Wenn Ihre Anwendung auf einem statischen Dateiserver gehostet wird, müssen Sie a anstelle von a verwenden.

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

ReactDOM.render((
  <HashRouter>
    <App />
  </HashRouter>
), holder)

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

jsina
quelle
1
Der Artikel, auf den Sie verwiesen haben, war sehr hilfreich, da ich express.js verwendet habe. Dieser Code aus dem Artikel gab mir den Hinweis und die Lösung, neben dem "/" eine andere URL zu akzeptieren, da er ein Sternchen als Argument für die Funktion get () enthält. app.get ('*', (req, res) => {res.sendFile (path.resolve (__ dirname, 'index.html'))})
Jerameel Resco
5

Es hat bei mir funktioniert, ich brauche nur das Hinzufügen devServer { historyApiFallback: true }ist in Ordnung, brauche keine VerwendungpublicPath: '/'

Verwendung wie:

  devServer: {
    historyApiFallback: true
  },
kiss_von
quelle
3

Ich hatte das gleiche Problem. Was es für mich behoben hat, war das Bearbeiten meiner package.jsonDatei und darunterscripts: {

"build": "webpack -d && copy src\\index.html dist\\index.html /y && webpack-dev-server --content-base src --inline --port 3000"

Am Ende meines Webpack- buildCodes fügte ich hinzu, dass --history-api-fallback dies auch die einfachste Lösung für den Cannot GET /urlFehler zu sein schien

Hinweis: Wenn --history-api-fallbackSie das nächste Mal nach dem Hinzufügen erstellen, werden Sie eine Zeile in der Ausgabe bemerken, die so aussieht (mit welcher Indexdatei auch immer):

404s greifen auf /index.html zurück

Jared
quelle
2

Wenn Sie Express (nicht Webpack) verwenden, hat dies bei mir funktioniert.

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

Wenn Sie Webpack verwenden, überprüfen Sie Ihre Konfiguration in einem Teil der Serverkonfiguration auf das Attribut "contentBase". Sie können anhand dieses Beispiels Folgendes festlegen:

devServer: {
    ...
    contentBase: path.join(__dirname, '../')
    ...
}
Alex
quelle
1

Ich hatte auch Erfolg damit, indem ich ... historyApiFallback: true

devServer: {
    contentBase: path.join(__dirname, "public"),
    watchContentBase: true,
    publicPath: "/dist/",
    historyApiFallback: true
}
SheldonO'Reilly
quelle