I am new in reactjs
and I have a little project in reactjs
to play with and learn it. I need to have to type of headers which will be shown based o
While I am not familiar with Tomcat, what is most likely happening is that your server is looking for a /test/t
or /test/t/index.html
file, and since none exists, it is returning a 404 error.
When you use a browser history, you need to have a server that can handle routing. Typically this will be a wildcard (*
) route that returns your index.html
file (which in turn will return your bundled js as well as any other static files included in the index file).
One solution is to switch to using a hash router. If you are not able to do routing on the server (particularly relevant for people hosting static content), then hash routing is necessary. However, because you are using a server, you should be able to setup routing that will allow you to use a browser router.
As I said before, I am not familiar with Tomcat, so I will just describe what the configuration should be.
/test/*
(where * is any URL) should serve your index.html
file.I think an answer to the OP's question should address also the access to static resources via the default servlet.
In my understanding the problem appears in multi-view React applications where a Router is used to alter the page URL in order to reflect the state of the application. This is nice, but if you reload the page by accident you get 404 since there won't be any resource matching the altered URL. It also means such altered URLs can't be bookmarked as direct access to different application views. Unless, we get a little help from the server side.
There are more solutions possible, depending on how the access to static resources is handled, or the chosen implementation (filter, servlet or even JSP), but the basic idea is to serve the main application HTML file for every Routes defined in React.
Supposing you have you have two React Routes defined in your application:
<Route path={"view1"} component={View1} />
<Route path={"view2"} component={View2} />
You could create a RouterServlet to forward requests to /view1 or /view2 back to the context root (/), supposing you mapped the application here.
void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
request.getServletContext().getRequestDispatcher("/").forward(request, response);
}
You can configure it like this:
<servlet>
<servlet-name>RouterServlet</servlet-name>
<servlet-class>package.RouterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RouterServlet</servlet-name>
<url-pattern>/view1/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>RouterServlet</servlet-name>
<url-pattern>/view2/*</url-pattern>
</servlet-mapping>
For Tomcat versions below 8. You can just add a web.xml
file and route the 404 to index.html
.
webapps/[my-app-name]/WEB-INF/web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<display-name>my-app-name</display-name>
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
</web-app>
In my case I wanted a simple solution as with creating a customer error page. However that solution still sets a status code 404
which is not desired.
So I use a small jsp file which will set status code to 200
before outputting the SPA's index.html
.
I hope this helps someone else looking for a simple solution without returning status 404
.
web.xml
<error-page>
<error-code>404</error-code>
<location>/spa.jsp</location>
</error-page>
spa.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%
response.setStatus(200);
%><%@include file="./dashboard/index.html"%>
I have the same problem routing not working. If 404 not redirecting and loading the index.html problem. I tried several ways and finally found a solution which fixed my problem.
This worked for me on Tomcat 8
inside ROOT folder of Tomcat make a new folder WEB-INF and create web.xml
You can do this by
sudo gedit /opt/tomcat/webapps/ROOT/WEB-INF/web.xml
paste the below in the web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>your_display_name</display-name>
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
</web-app>
Restart the Tomcat. This fixed the routing problem for me. Hope this helps for someone I think. Thanks
First, you must be aware of the following differences when using react-router
.
When you enter localhost:3003/test/
in your browser, it will request the server, and then it will receive /test/index.html
, the js
bundle, css
, ...
After that, whenever you click an internal link (eg. localhost:3003/test/t/
), your browser will not request the server again. React-router
will resolve this client-side, re-render portions of the page, and update browser's address bar (using HTML5 pushstate()), without triggering another server request.
When you enter localhost:3003/test/t/
directly in the address bar, your browser will request the server, and Tomcat does not have /test/t/index.html
or so, and it returns a 404
. It's because Tomcat doesn't know anything about react-redux
nor javascript
.
A way to handle this is to configure 404
errors to be forward to /test/index.html
. It's probably how your webpack dev server is configured by default.
There is plenty of examples of doing this on apache, if you have one in front of our Tomcat.
Search for html5 pushstate apache config
.
Here is an example:
httpd.conf
:
...
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>
...
If you are using Tomcat alone, you may try to specify this in the web.xml
, inside your .war
file:
...
<error-page>
<error-code>404</error-code>
<location>/index.html</location>
</error-page>
...
Note that this is not a react-router
specific problem, every app that uses HTML5 pushstate()
needs to handle this somehow. Javascript servers may handle this more seamlessly though.