3

When I try to do a GET call to a subroute of my react application I get a 404. When I do this to my homepage it returns correctly the HTML. When just accessing the subroutes via the browser my webpage gets correctly rendered. I'm Using React version 16.9.0. I'm hosting the web application in Azure App service.

The reason for this question is to use an external program that can check for deadlinks in a website. At the moment I get 404's for every call to a subroute.

GET calls in Postman:

www.test.be => works

www.test.be/custom-route => gives a 404

This is my React Router Wrapper component:

import React from 'react';
import { Switch, Route } from 'react-router-dom';
import Home from 'home/containers/home-container.js';
import NotFoundPage from './error-pages/not-found-page';
import Questions from 'questions/containers/question-container.js';

const Body = () => {
  return (
    <Switch>
      <Route path="/" exact component={Home} />
      <Route path="/questions" component={Questions} />
      <Route component={NotFoundPage} />
    </Switch>
  );
};

export default Body;

This is my web.config file:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <httpRuntime requestPathInvalidCharacters="&lt;,&gt;,*,&amp;,:,\\,?" />
  </system.web>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
      </customHeaders>
    </httpProtocol>
    <rewrite>
      <rules>
        <rule name="HTTPSs">
          <match url="(.*)"/>
          <conditions>
            <add input="{HTTPS}" pattern="Off"/>
            <add input="{HTTP_HOST}" negate="true" pattern="^localhost" />
          </conditions>
          <action type="Redirect" url="https://{HTTP_HOST}/{R:1}"/>
        </rule>
        <rule name="ReactRoutes" stopProcessing="true">
          <match url=".*" />
          <conditions>
            <add input="{HTTP_METHOD}" pattern="^GET$" />
            <add input="{HTTP_ACCEPT}" pattern="^text/html" />
            <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          </conditions>
          <action type="Rewrite" url="/index.html" />
        </rule>
      </rules>
    </rewrite>
    <security>
      <requestFiltering allowDoubleEscaping="true"/>
    </security>
  </system.webServer>
</configuration>
Jim Peeters
  • 2,573
  • 9
  • 31
  • 53

4 Answers4

4

You don't provide complete details but If I understand correctly, it can help you to solve your problem, if you have this problem on the server and when you open the homepage it works correctly and when open a subroute it goes to 404 page, add this to your .htaccess file

RewriteBase /
RewriteRule ^index\.html$ - [L]
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
Erfan HosseinPoor
  • 1,049
  • 7
  • 9
2

This is because how reactjs applications gets deployed on your production WebServer.

Reactjs applications are served deployed on with single index.html. Entire entire react project is served from index.html (This is how 'www.test.be' works). React-router programmatically updates the browser URL based on which page you navigate.

When your visit 'www.test.be/custom-url', the request is first caught and processed by the webserver. The webserver is expecting HTML file named 'custom-url.html' doesn't find it. So webserver throws a '404' i.e. 'Page not found' error. The request is not forwarded to your ReactApp - so your ReactApp never gets a chance to process the request.

The solution depends on the type of hosting service you are using. Basically, you want to redirect all URLs to React App (index.html) so that React Application will get a chance to process 404.

Update your question with the hosting service you are using (such as netlify, heroku, aws etc) and I can update this answer with a solution suitable for that hosting service.

For instance, if the webhost is netlify, you can create a file called _redirect in public/ directory with the following content

/*  /index.html  200

That will redirect all traffic (*) to index.html

Meera Datey
  • 1,913
  • 14
  • 15
1

It happens because you don't have SSR (Server-Side Rendering). probably you're using CRA to create your ReactJs web application, so it works with CSR and the sub-routes couldn't be understood by server.

I don't mean bring SSR to your project, because you should be serious about using SSR for some special reasons. by the way, there is a very simple solutions for any kind of servers, you should redirect all requests to the index.html then react-router can understand the sub-route in the client:

Redirect all to index.html:

  • PM2 server:

    pm2 start [path-to-build-folder/app.js] --spa
    
  • Serve:

    serve -s [path-to-build-folder/app.js]
    
  • IIS:

    <!--web.config url rewrite-->
    <configuration> 
      <system.webServer>
          <rewrite>
              <rules>
                  <rule name="Redirect To Index" stopProcessing="true">
                      <match url=".*" />
                      <conditions>
                          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                      </conditions>
                      <action type="Rewrite" url="/index.html" />
                  </rule>
              </rules>
          </rewrite>
      </system.webServer>
    </configuration>
    

I don't know how you deployed your ReactJs web application, because some time DevOps specialist use running ReactJs app by using serve, pm2 or node under a special port for example: 8008 then by using IIS proxy try to connect the web application to local process, so by calling the port 80 user will be able to see the website. Also, you can directly serve the application by serving index.html in the IIS, and totally your solution is redirecting all requests to index.html.

Hope this answer helps you.

AmerllicA
  • 29,059
  • 15
  • 130
  • 154
0

try this web.config :)

<?xml version="1.0" encoding="utf-8"?> 
<configuration>
<system.webServer>
  <rewrite>
    <rules>
      <rule name="React Routes" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
          <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
          <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
        </conditions>
        <action type="Rewrite" url="/" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

</configuration>
Sektowr
  • 356
  • 1
  • 8