Edited at

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

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