11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Nuxt.jsでステータスコードによって独自の処理とエラーページを使い分けたい

Last updated at Posted at 2019-10-27

Nuxt.jsには、pageコンポーネント中でエラーが発生した時に遷移するためのエラーページが用意されています。

404用のページなどを用意する必要がないので非常に便利ですが、

「ログインの失敗時に、401(認証エラー)なら画面上部にメッセージを出す、500(サーバーエラー)ならNuxtのエラー画面に遷移する」

といった処理をしたいときは、全てのエラー時にエラーページに遷移されたら困ります。

このように、エラーのステータスコードによって、独自の処理とNuxtのエラーページを使い分けるための処理を書いてみました。

例: ログインページ

認証エラー(401)→独自の処理
その他エラー(401以外)→エラーページへ遷移する。かつ、ステータスコードをエラーページで表示させる

全体のコード(解説は後ほど)

pages/login.vue


<template>
      <div>
        <header>
          <div>
            <p>ログイン</p>
          </div>
        </header>
        <div>
          <p>登録ID</p>
            <input v-model="id" type="text" placeholder="ログインID" />
            <p>パスワード</p>
            <input v-model="pass" type="password" placeholder="8文字以上" />
            <button @click="handleClickLogin">
              ログイン
            </button>
        </div>
      </div>
    </template>
    <script>
    import { mapGetters, mapActions } from "vuex";
    
    export default {
      data() {
        return {
          id: "",
          pass: "",
          message: null
        };
      },
      methods: {
        async handleClickLogin() {
            try {
              await this.clientLogin({ id: this.id, pass: this.pass });
            } catch (e) {
    	    this.$nuxt.error(e.message);
            }
        },
        ...mapActions(["clientLogin"])
      }
    };
    </script>

store/index.js


export const state = () => ({
      token: null,
      ID: null
    });
    
    export const getters = {
      token: state => state.token,
      ID: state => state.kenpoID
    };
    
    export const mutations = {
      setClient(state, { ID, token }) {
        state.ID = ID;
        state.token = token;
      },
    };
    export const actions = {
      async clientLogin({ commit, dispatch }, params) {
        try {
          const response = await this.$axios.post(`/api/client/login`, params);
          const { token, ID } = response.data;
          commit("setClient", { ID, token });
          this.$router.push(`/clients/${ID}`);
        } catch (error) {
          if (error.response.status == "401") {
    	     //401の時の処理をここに書く
             //実際はフラッシュメッセージを呼び出しましたが今回は省略
          } else {
            throw new Error(error.response.status);
          }
        }
      }
    }

pages/error.vue


<template>
  <div>
    <div>
      <div>
        <h1 v-if="error && error.statusCode === 404">
          {{ error.statusCode }}: ページが見つかりません
        </h1>
        <h1 v-else-if="error && error.message">
          {{ error.message }}: エラーが発生しました
        </h1>
      </div>
    </div>
  </div>
</template>
<script>
import { mapActions } from "vuex";

export default {
  layout: "defaultForError",
  props: {
    error: {
      type: Object,
      default: null
    }
  }
};
</script>

全体の流れ

1. pageでのログイン処理

pages/login.vue中で「ログイン」をクリックすると、handleClickLoginが呼ばれclientLoginにログイン情報が渡されます。


      methods: {
        async handleClickLogin() {
            try {
              await this.clientLogin({ id: this.id, pass: this.pass });
            } catch (e) {
    	    this.$nuxt.error(e.message);
            }
        },
        ...mapActions(["clientLogin"])
      }

2.clientLoginでログイン情報をpost

store中でログイン処理が成功した場合は、帰ってきたIDとトークンをstateに保存して、個々のユーザーページに遷移します。
何らかのエラーが発生した時はcatchに飛びます。

          async clientLogin({ commit, dispatch }, params) {
            try {
              const response = await this.$axios.post(`/api/client/login`, params);
              const { token, ID } = response.data;
              commit("setClient", { ID, token });
              this.$router.push(`/clients/${ID}`);
            } catch (error) {
              if (error.response.status == "401") {
        	     //401の時の処理をここに書く
              } else {
                throw new Error(error.response.status);
              }
            }
          }

3.catch内で、error中のステータスコードによって処理を振り分ける

401の場合は、ユーザーに認証エラーである旨を伝えて再度ログインを試みてほしいのでエラーページには飛ばしません。フラッシュメッセージを出すなどの処理をここに書きます(省略)。

その他のエラーの場合はエラーページに遷移させたいので、まずはstore内で例外を発生させて、handleClickLoginのcatchに飛びます。


 throw new Error(error.response.status);

この時、エラーオブジェクトの第一引数としてステータスコードを渡しておきます。

4.pages/login.vue内のcatchへ飛ぶ


      methods: {
        async handleClickLogin() {
            try {
              await this.clientLogin({ id: this.id, pass: this.pass });
            } catch (e) {
              this.$nuxt.error(e.message);
            }
        },
        ...mapActions(["clientLogin"])
      }

このcatch(e)のeには、先ほどthrow new Errorで投げたエラーオブジェクトが入っています。

先ほど第一引数として渡したステータスコードはe.messageで取得できるので、ステータスコードを引数としてthis.$nuxt.errorでNuxtのエラー画面を呼びます。

5.エラー画面での処理

先ほど引数e.messageとして渡したステータスコードは、errorオブジェクトのmessageプロパティに入っているので、error.messageで取得できます。

参考: https://github.com/nuxt/nuxt.js/blob/dev/packages/vue-app/template/components/nuxt-error.vue

            <h1 v-if="error && error.statusCode === 404">
              {{ error.statusCode }}: ページが見つかりません
            </h1>
            <h1 v-else-if="error && error.message">
              {{ error.message }}: エラーが発生しました
            </h1>

上半分のerror.statusCodeは、ルーティングにないパスを指定すると呼ばれる部分です。
Nuxtにあらかじめ入っている機能を使うために残しています。

下半分は、this.$nuxt.errorを経由してmessageプロパティ付きのエラーオブジェクトが呼ばれた時の処理です。error.messageに入っているステータスコードを表示することで、エラーページ中にステータスコードを表示させることができました!

11
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?