Vue Routerで404 NotFoundを実現する

公開 :
最終更新 :

Vue Routerで404 Not Foundページを実現するもっとも単純な方法は以下です。Vue Routerは先に定義したルートに優先してマッチングするため、最後にどんなURLにもマッチするルートを記述して404 Not Foundに紐づけることできます。

import Vue from 'vue'
import Router from 'vue-router'
import Top from '@/components/Top'
import NotFound from '@/components/NotFound'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: Top
    },
    {
      path: '*',
      component: NotFound
    }
  ]
})

ところが、この方法ですと、動的ルートマッチングを行うときに漏れがでてきます。
例えば以下の場合に/user/nyanにアクセスして、もしデータベースにnyanというユーザが存在しない場合はどうなるでしょう。404に紐づけることができません。

import Vue from 'vue'
import Router from 'vue-router'
import Top from '@/components/Top'
import User from '@/components/User'
import NotFound from '@/components/NotFound'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: Top
    },
    {
      path: '/user/:id',
      component: User
    },
    {
      path: '*',
      component: NotFound
    }
  ]
})

動的ルートマッチングの404

動的ルートマッチングの場合も404 Not Foundを実現する最も単純な方法はリダイレクトを用いることです。
まず、ルーティングは下記のように設定します。

import Vue from 'vue'
import Router from 'vue-router'
import Top from '@/components/Top'
import User from '@/components/User'
import NotFound from '@/components/NotFound'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/404',
      component: NotFound
    },
    {
      path: '/',
      component: Top
    },
    {
      path: '/user/:id',
      component: User
    },
    {
      path: '*',
      redirect: '/404'
    }
  ]
})

こうしておけば、ユーザが存在しない場合はrouter.replace('/404')とするだけで404 Not Foundが実現できます。

動的ルートマッチングでURLを書き換えない404

前節の方法で404は動きとして実現できますが、URLが必ず/404に書き換わってしまいます。
URLを書き換えずに404 Not Foundを実現する方法は・・・残念ながら現バージョンのVue Routerではありません(たぶん)。
ここで議論されているような機能が実装されれば今後できるようになるかと思います。

しかたがないので、Vue Routerを用いずに代替え案で実現します。
まず、ルーティングは以下のように設定します。

import Vue from 'vue'
import Router from 'vue-router'
import Top from '@/components/Top'
import User from '@/components/User'
import NotFound from '@/components/NotFound'

Vue.use(Router)

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      component: Top
    },
    {
      path: '/user/:id',
      component: User
    },
    {
      path: '*',
      component: NotFound
    }
  ]
})

これで、/user/:id以外はURLを書き換えない404が実現できます。
ではUserコンポーネントを以下のようにすることでユーザが存在しないときも404が実現できます。

<template>
  <div>
    <not-found v-if="notFound"/>
    <div v-else>
      ...
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import NotFound from '@/components/NotFound'

export default {
  name: 'User',
  data () {
    return {
      notFound: false
    }
  },
  components: {
    'not-found': NotFound
  },
  mounted () {
    axios
      .get('./api/user?id=' + this.$route.params.id)
      .then(response => {
        ...
      }).catch(() => {
        this.notFound = true
      })
  }
}
</script>

今後のVue Routerに期待です!