Help us understand the problem. What is going on with this article?

【Vue】axiosで、デフォルトでCSRFトークンを設定できるようにする

More than 1 year has passed since last update.

VueとRailsで開発していると, axiosでPOSTリクエスト等を送ったときに以下のエラーが出るかと思います。

422 (Unprocessable Entity)

csrfトークン対策しなければならないのですが、エラーを防ぐ方法はいくつかあります。

Railsの場合は、protect_from_forgeryをコメントアウトすれば解決します。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # protect_from_forgery with: :exception ← コメントアウトする
end

手っ取り早い対処法ですが、CSRF対策を無効にしてしまうため、根本的な解決策になりません。

CSRF対策するためには、ヘッダーにトークンを含める必要があります。

import axios from 'axios'

axios.defaults.headers.common = {
    'X-Requested-With': 'XMLHttpRequest',
    'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content')
};

これでも良いのですが、これを毎回axiosを記述するたびに定義するのは面倒で増えるたびに見通しが悪くなります。
なので、このcsrf-tokenが自動でリクエストヘッダーに入るようにしてみました。

プラグインを作る

適当にpluginsフォルダを作って、以下ののように記述します。

app/javascript/packs/plugins/vue-axios.js
const VueAxiosPlugin = {}
export default VueAxiosPlugin.install = function(Vue, { axios }) {
  const csrf_token = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
  axios.defaults.headers.common = {
    "X-Requested-With": "XMLHttpRequest",
    "X-CSRF-Token": csrf_token
  }

  Vue.axios = axios
  Object.defineProperties(Vue.prototype, {
    axios: {
      get () {
        return axios
      }
    }
  })
}

ここでcsrf-tokenを設定してます。

後はこのプラグインをエントリーファイルにimportすれば、
Vue.useのタイミングでVueAxiosPlugin.installが呼び出されるようになります。

index.js
import Vue from "vue/dist/vue.esm";
import axios from "axios"; // 追加
import VueAxiosPlugin from "./plugins/vue-axios";  // 追加
import App from "./components/App.vue";

Vue.use(VueAxiosPlugin, { axios: axios }) // 追加

new Vue({
  el: "#app",
  render: h => h(App),
})

Vue.use(VueAxiosPlugin, { axios: axios })ではimportしてきたaxiosを引数に渡してるのでimport axios from "axios";を忘れないようにしましょう。

公式参考

axios実行ファイル

export default {
  methods: {
    postComment () {
      const params = { 
        comment: {
          email: "テストコメント",
        }
      }
      axios.post("users/sign_in", params)
        .then(res => {
          console.log(res)
        })
    }
  }
}

Vueインスタンスが作られるタイミングでaxiosが設定されてるため、
いちいちヘッダーにcsrfトークンを含める必要もありません。

これでだいぶスッキリしましたね。

参考: https://tech.medpeer.co.jp/entry/2018/02/26/080000

ngron
目がしんどい
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away