React-router v4 - cannot GET *url*

2019-01-31 00:27发布

问题:

I started to use react-router v4. I have a simple <Router> in my app.js with some navigation links (see code below). If I navigate to localhost/vocabulary, router redirects me to the right page. However, when I press reload (F5) afterwards (localhost/vocabulary), all content disappear and browser report Cannot GET /vocabulary. How is that possible? Can somebody gives me any clue how to solve that (reload the page correctly)?

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)

回答1:

I'm assuming you're using Webpack. If so, adding a few things to your webpack config should solve the issue. Specifically, output.publicPath = '/' and devServer.historyApiFallback = true. Here's an example webpack config below which uses both of ^ and fixes the refresh issue for me. If you're curious "why", this will help.

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

I wrote more about this here - Fixing the "cannot GET /URL" error on refresh with React Router (or how client side routers work)



回答2:

Just to supplement Tyler's answer for anyone still struggling with this:

Adding the devServer.historyApiFallback: true to my webpack config (without setting publicPath) fixed the 404/Cannot-GET errors I was seeing on refresh/back/forward, but only for a single level of nested route. In other words, "/" and "/topics" started working fine but anything beyond that (e.g. "/topics/whatever") still threw a 404 on refresh/etc.

Just came across the accepted answer here: Unexpected token < error in react router component and it provided the last missing piece for me. Adding the leading / to the bundle script src in my index.html has solved the issue completely.



回答3:

I was having the same issue, what fixed it for me was editing my package.json file, and under scripts: {

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

at the end of my webpack build code I added --history-api-fallback this also seemed like the easiest solution to the Cannot GET /url error

Note: the next time you build after adding --history-api-fallback you will notice a line in the output that looks like this (with whatever your index file is):

404s will fallback to /index.html



回答4:

If you use Webpack check your configuration in part of server configuration for the "contentBase" attribute. You can set by this example:

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


回答5:

I was having the same issue but got fixed after stopping and running webpack again.



回答6:

I also had success with this by adding ... historyApiFallback: true

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


回答7:

If your application is hosted on a static file server, you need to use a instead of a .

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



回答8:

If you are using Express (not Webpack), this worked for me..

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