LoginSignup
7

More than 1 year has passed since last update.

Nuxt.js × Railsでアプリ作成 CORS policy エラーの解決

Posted at

やりたいこと

  • Railsで作ったAPIに対してNuxt.js側から投稿する(前回の記事の続編です)

開発環境

ruby 2.6.5
Rails 6.0.3.4
node v14.7.0
yarn 1.22.4
フロント(Nuxt.js)のローカルサーバーのport番号は8000
API(Rails)のローカルサーバーのport番号は3000

投稿画面のマークアップ

  • sendボタンがクリックされたら、Postmanで投稿ができることを確認できたURI http://localhost:3000/api/v1/postsPOSTリクエスト を送るような処理を実装

app.gif

pages/index.vue
<template>
  <div class="container">
    <h4>新規投稿</h4>
    <div class="form-control">
      <span>Title</span>
      <input
        type="text"
        v-model="title"
      >
    </div>
    <div class="form-control">
      <span>Body</span>
      <input
        type="text"
        v-model="body"
      >
    </div>
    <div class="form-control">
      <button @click="postMessage">send</button>
    </div>
  </div>
</template>

<script>
export default {
  data: () => ({
    title: null,
    body: null,
  }),
  methods: {
    postMessage() {
      const url = 'http://localhost:3000/api/v1/posts';
      const post = {
        title: this.title,
        body: this.body,
      };
      this.$axios.post(url, { post })
        .then(res => console.log(res.status))
        .catch(error => console.log(error));
    },
  }
}
</script>

<style>
.container {
  width: 60%;
  max-width: 600px;
  margin: 0 auto;
}
.form-control {
  margin: 20px 0;
}
h4 {
  text-align: center;
}
span {
  width: 4em;
  display: inline-block;
}
input[type="text"] {
  width: calc(100% - 6em);
}
button {
  margin: auto;
  display: block;
}
</style>

CORSでのエラーになる時の解決方法

  • 上記で実装すると、console.logに下記が出力される

Access to XMLHttpRequest at 'http://localhost:3000/' from origin 'http://localhost:8000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

なぜ正しくリクエストが送れていないのか?
結論
Nuxt側(フロント側)からそのままURIを指定してしまうと CORSの制限がかかっているため 正しくリクエストが送れていない

CORSとは

オリジン間リソース共有Cross-Origin Resource Sharing (CORS) は、追加の HTTP ヘッダーを使用して、あるオリジンで動作しているウェブアプリケーションに、異なるオリジンにある選択されたリソースへのアクセス権を与えるようブラウザーに指示するための仕組みです。
ウェブアプリケーションは、自分とは異なるオリジン (ドメイン、プロトコル、ポート番号) にあるリソースをリクエストするとき、オリジン間 HTTP リクエストを実行します。

MDNより抜粋

CORS (オリジン間リソース共有) の問題を解決する

Nuxt公式ページに書いてある方法をそのまま実施します
※ 公式ページではnpmでインストールしていますが、今回はyarnで開発しているので下記コマンドを使います(npmやyarnのコマンドについてはこちらも参照ください)

// @nuxtjs/proxyのインストール
$ yarn add @nuxtjs/proxy
app/nuxt.config.js
modules: [
  '@nuxtjs/axios',
  '@nuxtjs/proxy'
],
proxy: {
  '/api': {
    target: 'http://localhost:3000',
    pathRewrite: {
      '^/api' : '/api/v1'
    }
  }
},

pathRewrite'^/api' : '/api/v1' の記述は、 @nuxtjs/proxyのgithubを参考にしています

上記では、vue側でリクエストとして指定している /api がつく接頭辞を /api/v1 にリライト(書き換え)て、http://localhost:3000 に送ってね、と指定しています

proxyやpathRewriteについての記述方法はこのサイトも参考になりました

Nuxt側の修正

上記でProxyを設定してCORSの問題を解決する設定をしたので、NuxtのファイルでリクエストをPOSTしている箇所を修正します

pages/index.vue
// 上の部分は省略
  methods: {
    postMessage() {
      const url = '/api/posts';
      const post = {
        title: this.title,
        body: this.body,
      };
      this.$axios.post(url, { post })
        .then(res => console.log(res.status))
        .catch(error => console.log(error));
    },
  }
// 以下省略

const url = '/api/posts'; と訂正する
※ Proxyの設定、pathRewriteの設定により、http://localhost:3000/api/v1/posts にリクエストして、と変換される

Rails側の修正

api/app/controllers/api/v1/posts_controller.rb
# 上の部分は省略
  private

  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    params.require(:post).permit(:title, :body)
  end
end

送られてくるパラメーターは、Nuxt側でこのようなオブジェクト型で指定しているため、require(:post)をする必要がある

pages/index.vue
const post = {
  title: this.title,
  body: this.body,
};

※このオブジェクト名がhogeだったら、require(:hoge)となる

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
What you can do with signing up
7