Search code examples
vue.jstomcathttp-status-code-404routerbrowser-history

Vue 2 router history-mode returing 404 error


I have a vue app with history mode running in tomcat. When visiting www.mywebapp.com/faq or mywebapp.com/other or ../post/99 etc it first seems to be working fine. Refreshing the page seems to be working fine aswell.

However when looking closer in the browser console i see that i got an error message.

"Failed to load resource: the server responded with a status of 404 ()"

The page is returning a 404 error for a split second before it redirects me and then the page loads.

On very slow internet connections the 404 error is there for a longer time before it loads.

Anyone know what i am missing here? I have added the following code to try to handle it but without success.

My router looks like this:

  export const router = new Router({
  mode: 'history',
  base: '/',
  routes: [
  {
  name: 'home',
  path: '/',
  component: Home
  },
  ....,
  {
   path: '*',
  component: ErrorLanding,
  name: 'NotFound'
  },
  ],
  scrollBehavior(to, from, savedPosition) {
      return {x:0, y: 0}
  }
  });
  router.beforeEach((to, from, next) => {
   const publicPages = ['/', '/login', '/register', 
       '/help', '/ticket', '/about' ];
   const authRequired = !publicPages.includes(to.path);
   const loggedIn = localStorage.getItem('user');
    const redirect = to.path;

   if (authRequired && loggedIn === null) {
    if(to.meta.authRequired === false) {
      next();
    }
    else
    next({ name: 'Login', query: { redirect: redirect } });

    } else {
    next();
    }
   });

my vue.config.js looks like this:

   module.exports = {
   devServer: {
   port: 80,     
   proxy: "http://localhost/*"
   },
   publicPath: process.env.NODE_ENV === 'production'
   ? '/'
   : '/'
   }

and finally, i have a web.xml file in dist/ROOT/WEB-INF/ with the following code:

  <?xml version="1.0" encoding="ISO-8859-1"?>
   <web-app xmlns="http://java.sun.com/xml/ns/javaee" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
   version="3.0" 
   metadata-complete="true">
  <display-name>my app</display-name>
  <description>
     this is my app description
  </description>
  <error-page>  
   <error-code>404</error-code>  
   <location>/</location>  
  </error-page>  
</web-app>

update

When i add this line of code to server.xml

   <Valve 
   className="org.apache.catalina.valves.rewrite.RewriteValve"/>

and create a rewrite.config file that i add to Catalina/localhost/ with this info:

   RewriteCond %{REQUEST_PATH} !-f
   RewriteRule ^/(.*) /index.html 

It is working, and i dont get any error message any more. But now i have a new issue. My arrays that are being populated via Vuex are returning infinite loops. How can this be?

Update

I have tried to add this to the rewrite.config file:

RewriteRule ^/api1/ - [L,NC]
RewriteRule ^/api2/ - [L,NC]
RewriteRule ^/api3/ - [L,NC]
RewriteRule ^/api4/ - [L,NC]
RewriteRule ^/api5/ - [L,NC]
RewriteRule ^/api6/ - [L,NC]
RewriteCond %{REQUEST_PATH} !-f
RewriteRule ^/(.*) /index.html

update SOLVED Below had to be added to the rewrite.config file.

 RewriteRule ^/myapi1/.* - [L,NC]
 RewriteRule ^/myapi2/.* - [L,NC]
 RewriteRule ^/myapi3/.* - [L,NC]
 RewriteRule ^/myapi4/.* - [L,NC]
 RewriteRule ^/myapi5/.* - [L,NC]
 RewriteRule ^/host-manager/.* - [L,NC]
 RewriteRule ^/manager/.* - [L,NC]
 RewriteCond %{REQUEST_PATH} !-f
 RewriteRule ^/(.*) /index.html

Big thanks to @Michal Levy for help!!


Solution

  • Problem is result of using history mode of Vue Router and is very well described in the docs

    When using history mode, the URL will look "normal," e.g. http://oursite.com/user/id. Here comes a problem, though: Since our app is a single page client side app, without a proper server configuration, the users will get a 404 error if they access http://oursite.com/user/id directly in their browser. To fix the issue, all you need to do is add a simple catch-all fallback route to your server. If the URL doesn't match any static assets, it should serve the same index.html page that your app lives in.

    There are also lot of examples how to do it for lot of servers - not for Tomcat tho...

    To configure "SPA fallback" (common name for this) in Tomcat you must:

    1. Configure the RewriteValve in server.xml

    Edit the ~/conf/server.xml to add the below Valve inside the Host section as below:

    <Host name="localhost"  appBase="webapps" unpackWARs="true" autoDeploy="true">
      <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />
    </Host>
    
    1. Write the rewrite rule in rewrite.config

    Create directory structure — ~/conf/Catalina/localhost/ and create the rewrite.config file inside it with the below content:

    RewriteCond %{REQUEST_PATH} !-f
    RewriteRule ^/(.*) /index.html
    

    Source

    Note: Beware that above rewrite rule causes your server to return index.html for any request that does not match "regular file" (see Rewrite Valve Docs). So if your server also serves some kind of API (REST for example), you need to modify rewrite rules to not to rewrite requests to API.

    For example if your API is served on /api/..., your rewrite rules should look like this:

    # match any URL starting with `/api/`, do not rewrite and don't process other rules...
    RewriteRule ^/api/ - [L]
    RewriteCond %{REQUEST_PATH} !-f
    RewriteRule ^/(.*) /index.html