Express status 404 with react-router

express and react-router
react-router 404
react router 301 redirect
react browserrouter reload 404
react-router 404 on refresh
express render react app
react express example
react router redirect

I have an express server that handles: 1 API route and rendering my initial index.html to include bundle.js holding my React/React-Router/Redux application.

As it stands, it is impossible to 404 on my web page as I have a catch all:

app.use(function (req, res) {
  return res.render('index')
})

In order for react-router's NoMatch to work I need to send a 404 code.

My routes are as follows:

Express — /api/test/:x/:y

React Router — :x/, :x/:y

What I am essentially trying to achieve is, if the user ever goes to a URL of: :x/:y/z/and/further then return a 404, unless what they've gone to is /api/test/:x/:y

Questions:

  1. How can I match routes, excluding my API routes, preferably in a scalable way, returning appropriate status codes?
  2. For something so simple, is there significant overhead in setting this up on a subdomain? Would that even alleviate the issue? Would I face issues when the app grows?

Take a look at react-router server side rendering docs: reacttraining.com/react-router/web/guides/server-rendering

Solution:

  1. Extract routes to separate files and require it in express app
  2. Add a middleware in express app that check url in express using match function from react-router. It should be written after middlewares that responsible for API routes.
  3. In case there is no appropriate routes for request url, response with 404.

So, middleware should be similar to this:

// origin code from https://github.com/reactjs/react-router/blob/master/docs/guides/ServerRendering.md
// this is ES6, but easily can be written on a ES5.

import { match, RouterContext } from 'react-router'
import routes from './routes' 

var app = express();

// ...

app.use((req, res, next) => {
  match({ routes, location: req.url }, (error, redirectLocation, renderProps) => {
    if (error) {
      res.status(500).send(error.message)
    } else if (redirectLocation) {
      res.redirect(302, redirectLocation.pathname + redirectLocation.search)
    } else if (renderProps) {
         // You can also check renderProps.components or renderProps.routes for
        // your "not found" component or route respectively, and send a 404 as
        // below, if you're using a catch-all route.

        // Here you can prerender component or just send index.html 
        // For prependering see "renderToString(<RouterContext {...renderProps} />)"
        res.status(200).send(...)
    } else {
      res.status(404).send('Not found')
    }
  })
});

If any routes change, you don't need to do something on express app, because you're using same code for frontend and backend.

Fixing the "cannot GET /URL" error on refresh with React Router and , [feature/documentation] v4 detect 404 in Server side rendering (or App.js import React from 'react'; import { Route, Switch } from 'react-router-dom'; In order to render this app from an express server I'd do the following:. A common use case for when you’re building an app with React Router is to have a “catch all” route that will be rendered if none of your other routes match. A good example of this is if you wanted your client-side router to render a 404 page.

You need to put your actual API routes above your catch-all so that they are picked up before it.

Basically, middlewares defined first take precedence over route complexity.

Once a response is sent to the client, Express will stop processing middleware unless an error is thrown or for some reason, next is manually called.

You can define a simple error handler like so:

app.use(function catchError(req, res, next, err) {
    console.error('Caught error', err);
    res.status(500).json({
        error: err
    });
});

ReactTraining/react-router, I am using react-router server-side to render my app. to duplicate my routes, to both be in react-router format and in my express.js server. For now, you can simply do a this.context.router.replace to a 404 route on your  Express.JS React.JS React-Router Create The Express App Backend In order to begin setting up our app, both node.js and npm need to have been installed. To start we will need to create a parent directory, which can be named anything you want. Here we will call ours react-express-example.

the router in express is a middleware so, the order is very important when you define your routes. In order to separate the API routes you can create a module to handle these and then create middlewares to catch others routes including one for a 404 response. Don't forget put the api routes first. This is an example:

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

var routes = require('./routes/api');
var app = express();
...

// handle the request for the API
app.use('/api', routes);
...

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: {}
  });
});


module.exports = app;

And the api route module:

var express = require('express');
var router = express.Router();

/* GET test page. */
router.get('/test/:x/:y', function(req, res, next) {
  res.render('test', { x: req.params.x, y: req.params.y });
});

module.exports = router;

Returning 404s from components · Issue #3210 · ReactTraining , Tagged with express, react, reactrouter, javascript. import React, { Component } from 'react'; import { Route, Switch } from 'react-router-dom'; import '. my app on heroku I am shown "Not Found" error (most probably 404). However it does not seem it is possible to return a 404 once RouterContext is started to render. Solution 1. Handle 404 before even beginning to render. Upside: Simple Drawback: Needs to duplicate my routes, to both be in react-router format and in my express.js server. Solution 2. Be able to return 404 from within react component.

Sound like you could just use the order of routs to your advantage.

app.get('/api/test/:x/:y', function(){})

app.get('/:x/:y', function(){})

app.get('/:x/:y/:err', function(res, req){ res.status(404).send('oops') })

This way the request will try /api/test then /something/something then if its /something/something/something-else it will fail.

Deploying a React app with React-Router and an Express Backend , 404, 401, or any other status. We can do the same thing as above. Create a component that adds some context and render it anywhere in the app to get a different  In Express, 404 responses are not the result of an error, so the error-handler middleware will not capture them. This behavior is because a 404 response simply indicates the absence of additional work to do; in other words, Express has executed all middleware functions and routes, and found that none of them responded.

I managed to get my React app with React Router v4 working with an express server running liquid.js similar to handlebars the solution would work the same way for any other template engine.

In your React App.js make sure you have the React Router v4 installed and set up like this:

import React, { Component } from 'react';
import { TransitionGroup, CSSTransition } from "react-transition-group";
import 'foundation-sites';
import {
  BrowserRouter as Router,
  Route,
  Switch
} from "react-router-dom";
import './assets/css/foundation.min.css';
import './assets/css/settings.scss';
import './assets/css/structure.css';
import './assets/css/owl-slider.css';
import './assets/fonts/fontawesome/all.css'; 


// ## COMPONENTS
import Header from './components/Header/header';
import Footer from './components/Footer/footer';

// ## PAGES 
import HomePage from './components/Pages/Home/homePage';
import AboutPage from './components/Pages/About/aboutPage';
import ServicesPage from './components/Pages/Services/services';
import ContactPage from './components/Pages/Contact/contact';


class App extends Component {


  render() {
    return (
      <Router>
        <div className="App page-a blur" id="page" data-toggler=".blur" >
          <Header/>
          <div className="pageWrapper">
          <Route render={({ location }) => (
              <TransitionGroup>
                <CSSTransition key={location.key} classNames="pageTransition" timeout={500}>
                  <Switch location={location}>
                    <Route exact path="/" exact component={HomePage} />
                    <Route path="/services" render={props => <ServicesPage {...props}/>} />
                    <Route path="/about" component={AboutPage} />
                    <Route path="/contact" component={ContactPage} />
                    <Route render={() => <div>Not Found</div>} />
                  </Switch>
                </CSSTransition>
            </TransitionGroup>
          )}/>
          </div>
          <Footer footerMessage="Liliana Alves // Sport &amp; Soft Tissue Therapist"/>
        </div>
      </Router>
    );
  }
}

export default App;

The above code will make sure that when the user navigates your React app and the routes are doing their job sending the user to a page they navigate, refresh or enter in the URLs manually.

In your express server app.js you want to define the main access root "/" to your react app "Do not use a wildcard * (asterisk) this will not work!" :

app.get('/', (req, res) => {

        res.status(200).sendFile(path.join(__dirname+'/react-site/build/index.html'));

}); //THE REQUEST CONTENT

Then if you would have a 404 in your express it would redirect your user back to React to handle the 404s using React Router, this method is done using an express error handler:

app.use((req, res, next) => {
    const error = new Error('Not Found'); //Error object
    error.status = 404;

    //res.render('./404'); by default in express applications you would render a 404 page

    res.status(200).sendFile(path.join(__dirname+'/react-site/build/index.html'));

    next(error);

});

I spent a decent time research to get it working if anybody thinks this should be improved or it might need more support in the error function please let me know.

Server Rendering, Learn how to show a 404 page in a client side routed react application if there is no route matching the URL. import React from 'react'; export default ( { staticContext = {} }) => { staticContext.status = 404; return <h1>Oops, nothing here!</h1>; }; Then, on the server, we can check for a status of 404 on the context object and serve the file with a status of 404 if our check evaluates to true: server/index.js.

Creating 404 page in react using React Router, A look at configuring React Router v4 to work with an Express with a HTTP status code of 404 when rendering the NotFound component. First  I'm not sure the router needs to change at all here, these are all questions for the app to answer. You can redirect to a 404 route. You can render a 404 view in the current route. You can send a 404 status code and render the current route on the server. You can redirect to a 404 route on the server.

Using React Router 4 with Server-Side Rendering, src/public/fav.ico") }) ] I'm exposing this generated index.html like this: app.use('/', express.static(__dirname)); I'm using, client-side, react-router, here are my  Define error-handling middleware functions in the same way as other middleware functions, except error-handling functions have four arguments instead of three: (err, req, res, next). For example: app.use(function (err, req, res, next) { console.error(err.stack) res.status(500).send('Something broke!')

Express status 404 with react-router and HTMLWebpackPlugin, The most common solution in building an Express/React application is to send a 404 status whenever a route isn't found within React Router. Related. Using Node.js to download files. How to download files using Node.js There are three approaches to writing a file downloader using Node: Using HTTP.get Using curl Using wget I have created functions for all of them.

Comments