In the routes declaration, I like to add this:
[
...
{ path: '/404', component: NotFound },
{ path: '*', redirect: '/404' },
...
]
Which will imply that if the user is navigated to a path which does not match any routes, it will be redirected to the «404» route, which will contain the «not found» message.
The reason I’ve separated it into 2 routes is so that you can also programmatically direct the user to the 404 route in such a case when some data you need does not resolve.
For instance, if you were creating a blog, you might have this route:
{ path: '/posts/:slug', component: BlogPost }
Which will resolve, even if the provided slug does not actually retrieve any blog post. To handle this, when your application determines that a post was not found, do
return this.$router.push('/404')
or
return router.push('/404')
if you are not in the context of a Vue component.
One thing to bear in mind though is that the correct way to handle a not found response isn’t just to serve an error page — you should try to serve an actual HTTP 404 response to the browser. You won’t need to do this if the user is already inside a single-page-application, but if the browser hits that example blog post as its initial request, the server should really return a 404 code.
Последнее обновление: 04.11.2020
Распространенной задачей в веб-приложениях является обработка несущеcтвующих путей, когда приложение не может сопоставить запрошенный адрес ни с одним из ресурсов приложения.
Рассмотрим, как это можно сделать во Vue 3.
<!DOCTYPE html>
<html>
<head>
<title>Маршрутизация во Vue 3</title>
<meta charset="utf-8" />
<style>
ul{list-style-type: none;padding: 0;}
li{display: inline-block;}
a{padding: 5px;}
a.router-link-active, li.router-link-active>a {
color: red;
}
</style>
</head>
<body>
<div id="app">
<ul>
<li><router-link to="/">Home</router-link></li>
<li><router-link to="/about">About</router-link></li>
</ul>
<router-view></router-view>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script src="https://unpkg.com/vue-router@next"></script>
<script>
const Home = { template: '<h2>Home Page</h2>' }
const About = { template: '<h2>About Page</h2>' }
const NotFound = { template: '<h2>Page Not Found</h2>' }
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/:pathMatch(.*)*', component: NotFound },
];
const router = VueRouter.createRouter({
history: VueRouter.createWebHistory(),
routes,
});
const app = Vue.createApp({});
app.use(router);
app.mount('#app');
</script>
</body>
</html>
Для обработки запросов к несуществующим ресурсам применяется компонент NotFound, который просто выводит соответствующую информацию:
const NotFound = { template: '<h2>Page Not Found</h2>' }
Этом компонент обрабатывает запросы по следующему маршруту:
{ path: '/:pathMatch(.*)*', component: NotFound }
В данном случае шаблон маршрута выглядит несколько замыславато: «/:pathMatch(.*)*». Фактически он означает, что вся часть после слеша расценивается
как параметр pathMatch, который может иметь произвольное количество символов и произвольное количество сегментов. То есть по сути он будет представлять запрос, которому
не соответствуют другие маршруты.
В итоге при обращении к несуществующему ресурсу запрос будет будет обрабатываться компонентом NotFound:

I think you should be able to use a default route handler and redirect from there to a page outside the app, as detailed below:
const ROUTER_INSTANCE = new VueRouter({
mode: "history",
routes: [
{ path: "/", component: HomeComponent },
// ... other routes ...
// and finally the default route, when none of the above matches:
{ path: "*", component: PageNotFound }
]
})
In the above PageNotFound component definition, you can specify the actual redirect, that will take you out of the app entirely:
Vue.component("page-not-found", {
template: "",
created: function() {
// Redirect outside the app using plain old javascript
window.location.href = "/my-new-404-page.html";
}
}
You may do it either on created hook as shown above, or mounted hook also.
Please note:
-
I have not verified the above. You need to build a production version of app, ensure that the above redirect happens. You cannot test this in
vue-clias it requires server side handling. -
Usually in single page apps, server sends out the same index.html along with app scripts for all route requests, especially if you have set
<base href="/">. This will fail for your/404-page.htmlunless your server treats it as a special case and serves the static page.
Let me know if it works!
Update for Vue 3 onward:
You’ll need to replace the '*' path property with '/:pathMatch(.*)*' if you’re using Vue 3 as the old catch-all path of '*' is no longer supported. The route would then look something like this:
{ path: '/:pathMatch(.*)*', component: PathNotFound },
See the docs for more info on this update.
I think you should be able to use a default route handler and redirect from there to a page outside the app, as detailed below:
const ROUTER_INSTANCE = new VueRouter({
mode: "history",
routes: [
{ path: "/", component: HomeComponent },
// ... other routes ...
// and finally the default route, when none of the above matches:
{ path: "*", component: PageNotFound }
]
})
In the above PageNotFound component definition, you can specify the actual redirect, that will take you out of the app entirely:
Vue.component("page-not-found", {
template: "",
created: function() {
// Redirect outside the app using plain old javascript
window.location.href = "/my-new-404-page.html";
}
}
You may do it either on created hook as shown above, or mounted hook also.
Please note:
-
I have not verified the above. You need to build a production version of app, ensure that the above redirect happens. You cannot test this in
vue-clias it requires server side handling. -
Usually in single page apps, server sends out the same index.html along with app scripts for all route requests, especially if you have set
<base href="/">. This will fail for your/404-page.htmlunless your server treats it as a special case and serves the static page.
Let me know if it works!
Update for Vue 3 onward:
You’ll need to replace the '*' path property with '/:pathMatch(.*)*' if you’re using Vue 3 as the old catch-all path of '*' is no longer supported. The route would then look something like this:
{ path: '/:pathMatch(.*)*', component: PathNotFound },
See the docs for more info on this update.
In this tutorial, you’ll learn how to add a custom 404 page to a Vue app (generated using the Vue CLI) with a basic Vue router configuration.
For this tutorial, I will be using a Vue router starter app generated using the Vue CLI. Here’s how the project file tree might look:

Right now, all we need to focus on are src/router/index.js and the components of the src/views folder.
This is how src/router/index.js should somewhat look:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
}
]
const router = new VueRouter({
routes
})
export default router
Enter fullscreen mode
Exit fullscreen mode
1) Visit the home page of the Vue app. /
What do you see?

2) Visit the about page of the Vue app. /about
What do you see?

3) Visit a random url of the app. Like /hi/someurl/404
What do you see?

(I customised my Vue app a lot, so it looks a whole lot different from the starter Vue router app, kindly excuse me for that 😅)
What do we notice from the above 3 scenarios?
If we visit a URL that exists, it correctly renders the component associated with that route. But if the URL does not exist, it just redirects it to the homepage, instead of showing some sort of error or a default 404 page. You might also have noticed that the URL of the default Vue app has /#/ suffixed to the URL.

We can fix all of these issues.
For the redirecting-to-homepage-when-it-doesn’t-exist case, we can create a custom 404 page, by specifying a wildcard route after all the other routes. First, we will have to create a 404 component.
In src/views folder, create a file named NotFound.vue. Add some basic text and images that makes it look like a 404 page.
<template>
<center>
<h1>Not Found!</h1>
<p>
<a href="/">Go home?</a>
</p>
</center>
</template>
<script>
export default {
name: 'NotFound'
}
</script>
<style scoped>
center {
margin: 15vw;
}
h1 {
color: var(--border);
font-size: 2em;
}
</style>
Enter fullscreen mode
Exit fullscreen mode
Once you have created NotFound.vue, in src/router/index.js add a wildcard route pointing towards the NotFound.vue component.
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import NotFound from '../views/NotFound.vue';
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '*',
name: 'Not Found',
component: NotFound
}
]
const router = new VueRouter({
routes
})
export default router
Enter fullscreen mode
Exit fullscreen mode
But we need to do one more thing, only then can we «successfully» create a 404 page.
The weird URL.
The «weird» URL is because the Vue router uses hash mode for routing by default. It uses the URL hash to simulate a full URL so that the page won’t be reloaded when the URL changes.
We can prevent the Vue router from doing this by enabling History mode.
const router = new VueRouter({
mode: 'history',
routes
});
Enter fullscreen mode
Exit fullscreen mode
The final src/router/index.js:
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from '../views/Home.vue';
import About from '../views/About.vue';
import NotFound from '../views/NotFound.vue';
Vue.use(VueRouter)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
},
{
path: '*',
name: 'Not Found',
component: NotFound
}
]
const router = new VueRouter({
mode: 'history',
routes
})
export default router
Enter fullscreen mode
Exit fullscreen mode
And now, our URL looks normal!

And that’s it! We have a fully functional 404 page now! Hope you enjoyed this tutorial!