2

I was looking at the react-router capability. To create a "Page Not Found" you use a <Switch> with the last entry set to a catch all like so:

<Switch>
  <Route path="/" component={Home}/>
  [...snip...]
  <Route component={PageNotFound}/>
</Switch>

However, that means the server just returned a 200 OK response to the client. In terms of SEO or just plain "let's follow the HTTP rules", I think it's broken.

Is that the norm on one page type of websites? Returning a soft 404?

Note that this would be if a user follows an external link from another website to a page on my React App website, page that was removed or never existed. While clicking links in the App., it doesn't matter. I do not see a way to have React return a 404 when the path is wrong. Am I correct?

Alexis Wilke
  • 15,168
  • 8
  • 60
  • 116
  • 1
    https://stackoverflow.com/questions/42237527/send-both-404-status-and-redirect-to-404-component-in-react-router – SakoBu Feb 16 '19 at 20:35

1 Answers1

2

How to redirect with a proper HTTP status code is discussed in the Server rendering part of the documentation. You could do something like the following:

const RedirectWithStatus = ({ to, status }) => (
  <Route render={({ staticContext }) => {
    // There is no `staticContext` on the client, so
    // we need to guard against that here
    if (staticContext)
      staticContext.status = status
    return <Redirect to={to}/>
  }}/>
)

const PageNotFound = () => (
  <RedirectWithStatus
    status={302}
    to="/"
  />
)

// Somewhere else in your app
<Switch>
  <Route path="/" component={Home}/>
  {/* ... */}
  <Route component={PageNotFound}/>
</Switch>

// On the server
const { createServer } = require('http')
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const { StaticRouter } = require('react-router');
const App = require('./App');

createServer((req, res) => {
  const context = {}

  const html = ReactDOMServer.renderToString(
    <StaticRouter
      location={req.url}
      context={context}
    >
      <App/>
    </StaticRouter>
  )

  if (context.url) {
    res.writeHead(context.status, {
      Location: context.url
    })
    res.end()
  } else {
    res.write(`
      <!doctype html>
      <div id="app">${html}</div>
    `)
    res.end()
  }
}).listen(3000)
Tholle
  • 83,208
  • 13
  • 152
  • 148
  • 1
    Okay! I see how you do SSR now. I could make things slow, though, but if I manage the cache properly, I should be good. – Alexis Wilke Feb 16 '19 at 22:06
  • @AlexisWilke Great! Yes, it's a bit unfortunate. You could also put the redirect in e.g. an nginx server and continue with just client side rendering if that is an option for you. – Tholle Feb 16 '19 at 22:08
  • This is only possible if you're using staticrouter... I am guessing it is not possible for most people to use a static router in their apps. – ambe5960 May 27 '20 at 00:25