[Vue Router] Error Handling and 404s

Zhentiw發表於2024-11-26

There are three different kinds of errors we need to catch in our application, and we will have different results for each of them.

  • When a user tries to navigate to a page that doesn’t exist.
  • When a user’s network connectivity fails.
  • When a user tried to go to an event that doesn’t exist.

Let’s deal with each of these problems one at a time.

🛑 Problem: The Generic Not Found 404

Right now when I go to a URL that doesn’t exist I get a blank page with no information about what is going on.

☑️ Solution: A Not Found Component

Let’s create a generic Not Found Component that we’ll redirect to when a path is accessed that doesn’t exist.

📃 /src/views/NotFound.vue

<template>
  <h1>Oops!</h1>
  <h3>The page you're looking for is not here.</h3>
  <router-link :to="{ name: 'EventList' }">Back to the home page</router-link>
</template>

Now we need to render this component when we go to a catch-all route, by updating our router.js file:

📃 /src/router/index.js

...
import NotFound from '@/views/NotFound.vue'

const routes = [
  ...
  {
    path: '/:catchAll(.*)',
    name: 'NotFound',
    component: NotFound
  }
]

As you can see, we’re creating a path that catches everything that hasn’t matched a current route our NotFound component, and then we are redirecting to the 404 path when we hit our new catch-all route.

🛑 Problem: What about when we try to view a non-existent Event?

Right now, when we go to an event that doesn’t exist, like /event/1233 we get a blank page

☑️ Solution: Creating a 404 page for a Non-Existent Event

First off in the NotFound component, I’m going to add a prop called resource which will default to page so if this component is loaded without the prop, the text will read “The page you’re looking for is not here”. This way when an event isn’t found, I can send in event as the value of resource and it will read “The event you’re looking for is not here.”

📃 /src/views/NotFound.vue

<script setup>
defineProps({
  resource: {
    type: String,
    required: true,
    default: 'page'
  }
})
</script>

<template>
  <div>
    <h1>Oops!</h1>
    <h3>The {{ resource }} you're looking for is not here.</h3>
    <router-link :to="{ name: 'EventList' }">Back to the home page</router-link>
  </div>
</template>

Now I need to update the router, so this route takes a prop:

📃 /src/router/index.js

...
{
  path: '/404/:resource',
  name: '404Resource',
  component: NotFound,
  props: true
},
...

And now I can redirect the user here if the API request when fetching an event returns an error:

📃 /src/views/Layout.vue

<script setup>
import { onMounted, ref, defineProps, computed } from "vue";
import EventService from "@/services/EventService.js";
import { useRouter } from "vue-router"

const router = useRouter();

...

onMounted(() => {
  EventService.getEvent(id)
    .then(response => {
      event.value = response.data
    })
    .catch((error) => {
      router.push({ 
        name: '404Resource', 
        params: { resource: 'event' } 
      })
    });
 })
 ...

🛑 Problem: Errors won’t always be 404

The only issue with this solution is that we’re assuming all network errors we receive are 404 errors. However, what if the user’s Internet just died or they’re on a super slow connection? We don’t want to give them a 404 error if their Internet dies, but that’s what’s going to happen right now, so let’s fix this.

☑️ Solution: A NetworkError component

We’ll start by creating a new component:

📃 /src/views/NetworkError.vue

<template>
  <div class="networkError">
    <h1>Uh-Oh!</h1>

    <h3>
      It looks like you're experiencing some network issues, please take a breath and
      <a href="#" @click="$router.go(-1)">click here</a> to try again.
    </h3>
  </div>
</template>

Notice how I’m using the $router.go(-1) method here to push the user back to the previous page which triggered the network error. We learned about this in our previous lesson.

Then we’ll add this to our router:

📃 /src/router/index.js

import NetworkError from "@/views/NetworkError.vue";

...
{
  path: '/network-error',
  name: 'NetworkError',
  component: NetworkError
},
..

And lastly we need to check which type of network error we’ve encountered so we can push to the appropriate path inside our Layout.vue:

📃 /src/views/event/Layout.vue

...
import { useRouter } from 'vue-router'
const router = useRouter()
...
onMounted(() => {
  EventService.getEvent(id)
    .then(response => {
      event.value = response.data
    })
    .catch(error => {
      if (error.response && error.response.status == 404) {
        router.push({
          name: '404Resource',
          params: { resource: 'event' }
        })
      } else {
        router.push({ name: 'NetworkError' })
      }
    })
})
...

相關文章