32

I am willing to use React-router for my application, and I am trying the example given in the doc first, which I copied below. Now when I go to localhost:3000/, I see "App" as expected, but every other page, such as localhost:3000/inbox returns "Cannot GET /inbox". What am I missing here ?

var About = React.createClass({
  render: function () {
    return <h2>About</h2>;
}});

var Inbox = React.createClass({
  render: function () {
    return <h2>Inbox</h2>;
}});

var App = React.createClass({
  render () {
    return (
      <div><h1>App</h1>
        <RouteHandler/>
      </div>
)}});

var routes = (
  <Route path='/' handler={App}>
    <Route path="about" handler={About}/>
    <Route path="inbox" handler={Inbox}/>
  </Route>
);
JulienD
  • 7,102
  • 9
  • 50
  • 84

7 Answers7

82

If you are using webpack-dev-server there is an option called history-api-fallback. If set to true 404s will fallback to /index.html.

Add the option to devServer section of the Webpack config like this:

devServer: {
    contentBase: 'app/ui/www',
    devtool: 'eval',
    hot: true,
    inline: true,
    port: 3000,
    outputPath: buildPath,
    historyApiFallback: true,
},

Link to Webpack docs: https://webpack.js.org/configuration/dev-server/

webpack-dev-server docs on Github: https://github.com/webpack/webpack-dev-server

NM Pennypacker
  • 6,704
  • 11
  • 36
  • 38
Tobi
  • 1,492
  • 1
  • 13
  • 20
22

I believe the issue is that you are making a http resource request:

GET /inbox HTTP/1.1
Host: localhost:3000

but are using client-side only routing. Are you intending on doing server side rendering too? You might need to change your router location to be HistoryLocation instead of HashLocation (the default).

The location prop of Router.run tells it where to match the routes against. If you're not running server side React, I believe you have to use Router.HashLocation (or just leave it blank).

If not, you are accessing your component the wrong way. Try using http://localhost:3000/#/inbox. It can take a little to familiarize yourself with React-Router but it is definitely worth it!

React Router Documentation - HashLocation

BradByte
  • 11,015
  • 2
  • 37
  • 41
  • Thanks for your answer. I am calling `Router.run(routes, Router.HistoryLocation, function (Handler, state) {...}`, I don't know about HashLocation. All I need is a different text to display depending on the name I add after the '/' (for instance, '/inbox'). The /#/ returns the same thing whatever I put after it (i.e. '/#/inbox' is treated the same as '/' and displays 'App': `state.params` is an empty object). – JulienD Aug 19 '15 at 14:57
  • Are you running React on the server? or are you just mounting React on a basic index.html file? – BradByte Aug 19 '15 at 15:00
  • I have an Apache instance that serves my frontend at localhost:3000, and the index.html there contains the React.js code. If it makes any sense. I also have a Python backend served at :8000 but I suppose it is unrelated. – JulienD Aug 19 '15 at 15:24
  • 1
    So basically, when you hit /index, the Apache server is looking for another resource to bring up, instead of keeping at the index.html file. You need to change your `router.Run` to use `Router.HashLocation` and then hit /#/inbox (same index.html document served). – BradByte Aug 19 '15 at 15:28
  • 2
    This is out of date with v2.x. Try following allowing here: https://github.com/reactjs/react-router/blob/master/docs/guides/Histories.md – Con Antonakos Mar 17 '16 at 02:37
  • the link is dead – Olli Jul 09 '20 at 18:49
2

Simplest option: use hash history instead. The urls stay are not very nice and if you need better SEO, I'd opt for server-side rendering as well.

If you're interested in detail about this, this answer was really helpful for me: React-router urls don't work when refreshing or writting manually

Capuchin
  • 3,465
  • 6
  • 28
  • 40
0

The request will be sent to the server, and the directory/file does not really exists so it will return 404, so you have to tell the server to return the index page for all requests, and react will handle the rooting :

if like me, you are hosting your react app on IIS, just add a web.config file containing :

<?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>

This will tell IIS server to return the main page to the client instead of 404 error.

Chtioui Malek
  • 11,197
  • 1
  • 72
  • 69
0

I came across the same problem, if you have a server that responds to requests and a HashRouter if you are using a static file server. Instead of using BrowserRouter use HashRouter its not the perfect fix, but should solve the cannot GET "/path" error. be sure to import HashRouter from 'react-router-dom'

render() {
    return (
        <div>
            <HashRouter>
                <Blog />
            </HashRouter>
        </div>
    );
}

source: https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/guides/basic-components.md

tony2tones
  • 1,422
  • 1
  • 18
  • 19
0

To add to those not helped by the answer: historyApiFallback: true works only for the first level of the url. So site.com/about will be redirected to index but site.com/about/me won't be. In this case, you need to add the rewrite option:

historyApiFallback: {
  rewrites: [
    { from: /./, to: '/index.html' }
  ]
}

This will match using a Regex expression all routes. Take care to also add this:

  output: {
    // ...
    publicPath: '/'
    //...
  },

Otherwise, the redirect will work to index.html, but index.html may have just bundle.js as the webpacked script, and will not read correctly. It should instead be '/bundle.js', which this config option will do.

David Min
  • 1,246
  • 8
  • 27
0

I had the same problem. Finely worked with webpack-dev-server, but not with express. The problem was in version of Express.js. I haven't noticed that it was beta (5.0.0-beta.1)

The solution is upgrading / downgrading to stable version (4.18.2 works fine).

Hope it helps!