React webconfig does not work on IIS server - reactjs

I have a web.config in my React application (imported in index.tsx):
<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" />
</conditions>
<action type="Rewrite" url="index.html" />
</rule>
</rules>
</rewrite>
<staticContent>
<remove fileExtension=".json" />
<remove fileExtension=".woff2" />
<remove fileExtension=".png" />
<remove fileExtension=".svg" />
<remove fileExtension=".ico" />
<remove fileExtension=".webmanifest" />
<mimeMap fileExtension=".json" mimeType="application/json" />
<mimeMap fileExtension=".woff2" mimeType="font/woff2" />
<mimeMap fileExtension=".png" mimeType="image/png" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".ico" mimeType="image/vnd.microsoft.icon" />
<mimeMap fileExtension=".webmanifest" mimeType="application/manifest+json" />
</staticContent>
</system.webServer>
</configuration>
The application is served on a subdomain (https://example.com/app/) and if I try to go to a subroute (like https://example.com/app/page1) which works perfectly fine in development mode, returns a page not found error on the server.
What am I doing wrong?

Since you provided less error message, I can only share some of my thoughts with you. My expression may not be accurate enough, hope you can understand my weak English.
Once you have a production build of your ReactJS application. It creates an index.html file that serves the entire application. All requests must be index.html first, and then React Router serves the content based on the query in the URL. When we access the app using the main URL, it hits index.html and works fine. If you go directly to a sub URL in your browser, the web server cannot find any file with that name. In this case, a 404 error message will be returned to the user.
Due to the update after version 6.0, the parent route must add /* , otherwise it will not navigate deeper, the parent route will no longer match, so the child route will never be rendered.
<Route path="/home" element={<Home/>}></Route>
change to
<Route path="/home/*" element={<Home/>}></Route>
If you expect all routes to be defined by React Router, only your backend, no matter what route, returns index.html. The rest is left to React Router. Then all you have to do is modify the backend server. If using HashRouter, change BrowserRouter to HashRouter. In this way, all requests will be directed to the index.html page, and the server side does not need any configuration.
In addition, the child routing page refreshes and reports an error, and normal access from the parent does not report an error. The reason may be that the js import path in the main file index.html is written as an absolute path; it needs to be imported by a relative path, or the address of a js file imported is wrong and needs to be checked.
I share with you a thread, it provides a very detailed explanation and potential solution.

Related

Redirect to root page on 403 response

I have a React App hosted on IIS. If I access an existing directory, such as <app_url>/static/, it returns a 403 response since there's no permission on that directory. I'd like to redirect the user to my root page (~/).
I have tried this:
<httpErrors>
<remove statusCode="403" subStatusCode="-1" />
<error statusCode="403" prefixLanguageFilePath="" path="/" responseMode="ExecuteURL" />
</httpErrors>
This kinda works, it does return the root page, however, it tries to download the React bundles from /static/ instead of '/' only.
What can I do here?
I used this rule and it worked:
<rewrite>
<rules>
<rule name="Redirect Static" patternSyntax="ExactMatch" stopProcessing="true">
<match url="static" />
<action type="Redirect" url="/" redirectType="Found" />
</rule>
</rules>
</rewrite>
(Thanks to #samwu)

Why does my HTTP GET call to a subroute in react app gives a 404 NOT Found instead of HTML?

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="<,>,*,&,:,\\,?" />
</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>
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]
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
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.
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>

No route registered for static file in Azure App Service

I have a Azure App Service that runs a ReactJS application. In the release pipeline I extract a zip file that contains my Cypress test results.
When I navigate to my Kudu console I can find the correct folder and files in my PS D:\home\site\wwwroot\e2e\mochawesome-report> folder. But when I navigate to
a video:
https://exampleUrl/e2e/mochawesome-report/video/onboarding.spec.js.mp4
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
But when I navigate to: https://exampleUrl.azurewebsites.net/e2e/mochawesome-report/screenshot/customer-card.spec.js/Customer card action tab -- can click on the account tab (failed).png
I can view the image.
Is there some configuration needed to view static files?
##EDIT##
Added my web.config:
<?xml version="1.0"?>
<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>
I'm pretty sure I found this somewhere on the web.
Something else I noticed. I can now open a .html and .css, .js and .png files but no .json, .woff, .woff2 and mp4.
You need to define file extensions to your web app.
Add these lines to your web.config, below your </rewrite>, then restart your Web App:
<staticContent>
<mimeMap fileExtension=".mp4" mimeType="video/mp4" />
</staticContent>
To add other extensions (like json):
<mimeMap fileExtension=".json" mimeType="text/plain" /
The result would be:
<staticContent>
<mimeMap fileExtension=".mp4" mimeType="video/mp4" />
<mimeMap fileExtension=".json" mimeType="text/plain" /
</staticContent>

How to redirect all routes to index page in web config on azure?

I am working with a react application deployed on azure. I am using react routers Browserhistory module. Currently I have the following rule in my web.config on azure:
<rule name="admin rule" stopProcessing="true">
<match url="admin" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" matchType="Pattern" pattern="api/(.*)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
And this works, the /admin route can be refreshed and manually entered in the browsers url window. If this rule isn't applied I can't refresh or manually enter the url. (see issue: React-router urls don't work when refreshing or writting manually)
But I actually want this to work for every route, also dynamic routes. for example:
/cart
/product/uniqueid
/example
Wich rule can I write so that every route is being rewritten to the index like in the admin route?
You should be able to swap your admin match rule for <match url=".*" /> right above your opening <conditions> tag. Check this blog post for more information.

IIS Redirect all request on root

I have reactjs application with react router. I dont want to use hash history and I encountered the issue with refreshing page creating 404 error (react-router is not loaded when refreshing and browser wants to fetch non-existent content thus 404). I found some solution and I want to redirect every request to root so server always fetch index.html with import tags first.
My folder structure is simple:
ROOT/
-- index.html
-- static/
-- js/
-- main.js
-- css/
etc...
I have this web.config rule found on this site:
<rewrite>
<rules>
<rule name="redirect all requests" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="index.html" appendQueryString="true" />
</rule>
</rules>
</rewrite>
This works very fine with URLs on first folder path, I mean all request like /items, /contact are good. But requests like /items/detail are broken because browser is looking into items folder and not into document root. Also very important thing is that my webpack generate index.html script tags in this manner: <script type="text/javascript" src="./static/js/main.js">.
Is it possible that src attribute is wrong because of that ./? How can I tell server (IIS 10) "hey don't look anywhere else but into document root?"
Thanks guys.
This is a solution I found were I have some paths I still want to handle by my IIS but the rest I want react to take care.
<configuration>
<system.webServer>
<rewrite>
<rewriteMaps>
<rewriteMap name="^(.*)$" />
</rewriteMaps>
<rules>
<rule
name="redirect all requests"
stopProcessing="true"
>
<match url="^(.*)$" />
<conditions logicalGrouping="MatchAll">
<add
input="{REQUEST_URI}"
pattern="/someOtherResourceIstillWantIIStoHandle(.*)$"
negate="true"
/>
<add
input="{REQUEST_FILENAME}"
matchType="IsFile"
negate="true"
/>
<add
input="{REQUEST_URI}"
pattern="/resourcecentre(.*)$"
negate="true"
/>
</conditions>
<action type="Rewrite" url="/index.html" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

Resources