運営者:そうすけ
愛媛出身の30代のブロガー兼ソフトウェアエンジニア。
主にフロント・バックの開発を行っています。
趣味はガジェットと植物。
フロントとバックで通信するときには設定が必要
RailsとNuxtで通信するのは異なるオリジン間の通信とになるのでCORS設定をしないといけません。
CORS設定を行う
CORSとは、オリジン間リソース共有(Cross-Origin Resource Sharing)の略で、異なるオリジン間でデータや画像、およびスクリプトファイルなどを共有する仕組みです。
通常ブラウザでは異なるオリジン間の通信は規約違反になっており、設定をしないとデータを共有することができません。
そもそもオリジンとはなんでしょう。
オリジンとは?
ウェブコンテンツのオリジン (Origin) は、ウェブコンテンツにアクセスするために使われる URL の スキーム (プロトコル)、 ホスト (ドメイン)、 ポート番号 によって定義されます。スキーム、ホスト、ポート番号がすべて一致した場合のみ、 2 つのオブジェクトは同じオリジンであると言えます。
https://developer.mozilla.org/ja/docs/Glossary/Origin
CORSについてはこのブログで丁寧に説明されていました。
方法
railsにrack.corsというGemをインストールする
クロスオリジン間の制約を設定してくるrack-corsをインストールします。
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
gem "rack-cors"
config\initializers\cors.rbができているので、ファイルを設定します。
この設定を行うことで、RailsのレスポンスのヘッダにAccess-Control-Allow-Originの値が付与されて、クロスオリジン操作ができるようになります。
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "ここにFrontのオリジン名(localhost:3000 など)"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head],
credentials: true
end
end
私も詳しくはないですが、許可するオリジンの他に、許可するリクエストメソッド、Cookie情報の許可など、このGemがその辺の設定を定義してくれます。
CORSのレスポンスヘッダについてはこちらが詳しかったです。
今回はNuxt3側は通信するのみなのであれば設定はいりません。
api通信してみる
userと表示させるApiを作ってみます。
rails g controller Api::V1::user
class Api::V1::UserController < ApplicationController
def index
render json: "user"
end
end
Rails.application.routes.draw do
# 追加
namespace :api do
namespace :v1 do
# api test action
resources :user only:[:index]
end
end
end
フロントは$Fetchを使用します
<template>
<div>{{users}}</div>
</template>
<script setup lang="ts">
//環境変数を取得
const config = useRuntimeConfig()
const users = ref<string[]>("")
async function getHello(){
//先にユーザーを用意
const { data } = await useFetch(config.public.apiOrigin+'/api/v1/users')
//ENVファイルの環境変数使っているがhttp://localhost:3000でもいい
users.value = data.value
console.log(data)
</script>
デベロッパーツールのNetworkタブのHeadersを見てみると、リクエストのヘッダに実際に乗っていることがわかります。
リクエストのヘッダー情報にX-Requested-With: ‘XMLHttpRequest’をいれる
CSRF対策になります。
class ApplicationController < ActionController::API
# CSRF対策
before_action :xhr_request?
private
# XMLHttpRequestでない場合は403エラーを返す
def xhr_request?
# リクエストヘッダ X-Requested-With: 'XMLHttpRequest' の存在を判定
return if request.xhr?
render status: :forbidden, json: { status: 403, error: "Forbidden" }
end
end
<template>
<div>{{users}}</div>
</template>
<script setup lang="ts">
//環境変数を取得
const config = useRuntimeConfig()
const users = ref<string[]>("")
async function getHello(){
//先にユーザーを用意
const { data } = await useFetch(config.public.apiOrigin+'/api/v1/users',
headers:{
'X-Requested-With': 'XMLHttpRequest',
} )
//ENVファイルの環境変数使っているがhttp://localhost:3000でもいい
users.value = data.value
console.log(data)
</script>
コメント