Search code examples
reactjsexpresshttp-status-code-404react-router-domserver-side-rendering

Set correct HTTP status with react router and SSR


I am trying to set HTTP status for NotFound component. My 404 component:

import React from 'react';
import { Route } from 'react-router-dom';

import styles from './index.module.scss';

const Status = ({ code, children }) => (
  <Route
    render={({ staticContext }) => {
      if (staticContext) staticContext.status = code;
      return children;
    }}
  />
);

const NotFoundContainer = () => (
  <Status code={404}>
    <div className={styles.error}>
      Oops! We can’t seem to find the page you are looking for.
    </div>
  </Status>
);

export default NotFoundContainer;

My <App /> has routes defined as:

  <Switch>
    ...
    <Route path='/about' component={About} />
    <Route component={NotFound} />
  </Switch>

I also have an SSR piece:

export default (req, res) => {
  ...
  frontloadServerRender(() =>
    renderToString(
      <Loadable.Capture report={m => modules.push(m)}>
        <Provider store={store}>
          <StaticRouter location={req.url} context={context}>
            <Frontload isServer={true}>
              <App />
            </Frontload>
          </StaticRouter>
        </Provider>
      </Loadable.Capture>
    )
  ).then(routeMarkup => {
    if (context.url) {
      // If context has a url property, then we need to handle a redirection in Redux Router
      res.writeHead(302, {
        Location: context.url
      });
      res.end();
    } else {
      // Otherwise, we carry on...
      const extractAssets = (assets, chunks) =>
      ...

I understood that this should be sufficient, SSR would return the correct status. However, I am not seeing it:

server listening on port 3000!
GET /sockjs-node 200 23.735 ms - -
GET /manifest.json 304 1.312 ms - -
GET /manifest.json 304 0.411 ms - -
GET /xxx 200 3.267 ms - -
GET /static/css/main.e6d4082b.chunk.css 304 0.689 ms - -
GET /static/js/2.90014d69.chunk.js 304 1.589 ms - -
GET /static/js/main.5d98d504.chunk.js 304 1.037 ms - -
GET /manifest.json 304 1.244 ms - -
GET /icons/favicon.ico 200 3.814 ms - -

GET /xxx should be returning 404, yet I get 200. What am I missing?


Solution

  • I was missing the last piece of code to make this work, below:

          if (context.status === 404) {
            res.status(404);
          }
          // We have all the final HTML, let's send it to the user already!
          res.send(html);
    

    Before we send the final response, we need to check the context status and set the status on the response when necessary, as above.