beta

Vue.jsのSPAで、メンテナンスページを出す

Vue.jsのSPAで、障害や予定メンテンスなどの時にメンテナンスページを出す方法をまとめました。APIサーバーからstatusを出すことで、リアルタイム制御ができて、PWAにも対応できます。

公開日:2019年8月28日

構成

  • フロント:Vue.js (example.com)
  • バックエンド:Node.js + Express (app.example.com)

フロー

  • App.vueが読み込まれた(created, watch)時にapp.example.comからstatusデータを取得する
  • メンテナンス状態なら、/maintenanceにリダイレクトする

バックエンド

単純に、status.jsonを返すだけです。中身は下記の通り。

正常時

{
  "status": 200
}

メンテナンス実行時

statusの値が通常と違うだけで問題ないのですが、どうせなので計画メンテナンスのケース用にスケジュール時刻を返してみます。

{
  "status": 503,
  "start": "2019.8.1 06:00:00",
  "end": "2019.8.1 07:00:00",
}

statusコードはHTTPのレンスポンスコードに合わせてますが、booleanでもなんでも良いと思います。

フロント(Vue.jsのSPA)

App.vue

各ViewはApp.vueを必ず通る設計にしておきます。

その上で、createdとwatchでメンテンス情報を取得するメソッド「chechMaintenance()」を実行させることで、読み込みやルートチェンジなどすべてのタイミングでメンテンスをチェックできます。

<script>
export default {
  name: "App",
  created () {
    this.chechMaintenance()
  },
  watch: {
    $route(to, from) {
    
    }
  },
  methods: {
    chechMaintenance(){
      const url = 'https://app.example.com/status.json'
      axios.get(url)
      .then((res) => {
        if(res.data.status !== 200){
          this.$router.push({name: 'Maintenance'})
        }
      })
      .catch((e) =>{
        this.$router.push({name: 'Maintenance'})
      })
    }
  }
}
</script>

単純にjsonファイルを返すだけのサーバーであれば、100msecもあれば返ってくるので、非同期通信でデータを取得すれば、アプリの動作には、体感上はほとんど影響ないと思います。

PWAでローカルに保存されていたとしても、App.vueを通過する度にチェックする仕組みになっているので、リアルタイムでチェックができます。

Maintenance.vue

リダイレクト先のメンテンスを通知するページです。Vue.jsはHTTPレスポンスを返せないので、503などのステータスコードを出すことはできませんが、短期間のメンテナンスであればこれでOKでしょう。

<template>
  <div>
    <h1>メンテナンス中です</h1>
    <p>現在システムメンテナンスを行なっています。大変ご迷惑をおかけしまして申し訳ございません。</p>
    <p>メンテナンス終了後に再度ページを読み込んでいただきますようお願いいたします。</p>
    <h2>メンテナンス予定</h2>
    <dl>
      <dt>開始</dt>
      <dd>{{start}}</dd>
      <dt>終了</dt>
      <dd>{{end}}</dd>
    </dl>
  </div>
</template>


<script>
import axios from 'axios';

export default {
  data() {
    return {
      start:'',
      end:''
    }
  },
  created () {
    this.getInfo()
  },
  methods: {
    getInfo(){
      const url = 'https://app.example.com/status.json'

      axios.get(url)
      .then((res) => {
        if(res.data.status == 200){
          this.$router.push({name: 'home'})
        }else{
          this.start = res.data.start
          this.end = res.data.end
        }
      })
      .catch((e) =>{
        this.$router.push({name: 'Maintenance'})
      })
    },
  }
}
</script>

単純にメンテナンスページ を表示するのであれば、「getInfo」メソッドのフローはまるっとなしで良いです。

課題

障害(サーバーダウン)

Vue.jsのSPAアプリの場合、フロントは静的サーバーなので、ダウンしたとしても、ファイルをまるっと別のサーバーに移してしまえば良いので問題は軽いですが、バックエンドAPI側は動的になることが多いので、こちらのサーバーに障害が起こった際は厄介です。

その際は、一時的にstatus.jsonだけを返すサーバーを立てて、そちらにapp.example.comのDNSを向けて対処するのが良いでしょう。

向け先のサーバーは、事前に用意してシャットダウンしておけば、より万全ですね。

長期的なメンテナンスの場合

あまり想定したくないですが、システムが取り返しのつかないことになったりして、数日以上のメンテナンスが必要になる場合は、しっかりとHTTPヘッダーで503を返す方がSEO的に良いです。

その場合は、フロントのVue.js・SPA側のpublicに、maintenance.htmlなどを用意して、サーバー側で503ステータスを付与すると良いと思います。


Vue.jsのSPAで、メンテナンスページを出す方法を見てきました。

SPA(特にPWA)はアプリの用意に動作するので、障害やメンテナンス用のフローはしっかり用意しておくと安心ですね。