CORSとは
CORSとはCross Origin Resource Sharing
の略語で、日本語で表すとオリジン間リソース共有
です。
ブラウザでは、セキュリティの観点から異なるオリジンを持つクライアント側からのHTTPリクエストを制限しています。
これを同一オリジンポリシー
と言います。
例えば、http://localhost:3001
でapiサーバーが立ち上がっており、http://localhost:3000
でクライアント側のサーバーが立ち上がっている場合に、クライアント側からapi側にリクエストをすると、オリジンが異なるため以下のようなエラーが出力されます。
Access to XMLHttpRequest at 'http://localhost:3001/api/v1/posts' from origin 'http://localhost:3000' has
been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
レスポンスヘッダーにAccess-Control-Allow-Origin
がないため、ブラウザでは制限されます。
異なるオリジンからのHTTPリクエストの可能にするには、バックエンド側での設定が必要です。
rack-cors
Railsでは、rack-cors
を使うことによって、オリジン間リソース共有が可能になります。
なぜRack
なのかというと、RailsがRackベースのアプリケーションであり、レスポンスを返す際にRackを噛ませているからです。
リクエストがあった場合、以下のような順番でWeb ServerからRails側までリクエストが送られます。
********************
Rails
********************
↑ ↓
********************
Rack
********************
↑ ↓
********************
Web Server
********************
rack-cors
を導入すると、Rackからのレスポンスのレスポンスヘッダーの設定を変更することができます。
どのように変化するのか、Rackミドルウェアを作成してRackからのレスポンスの中身を確認してみます。
↓ Rack Middlewareについてはこちら
今回はプロジェクトディレクトリ直下にミドルウェア用のファイルを作成します。
class SampleMiddleware
def initialize(app)
@app = app
end
def call(env)
status, headers, body = @app.call(env)
puts "-" * 15 + " " + "status" + " " + "-" * 15
puts status
puts ""
puts "-" * 15 + " " + "headers" + " " + "-" * 15
puts headers
return [status, headers, body]
end
end
@app.call(env)
によってRails側にリクエストが送られ、それに対するレスポンスがstatus
, request
, body
に入ります。
Rack
の設定ファイルであるconfig.ru
にミドルウェアを含めるようにします。
# This file is used by Rack-based servers to start the application.
require_relative "config/environment"
require_relative "sample_middleware" # <= 追加
use SampleMiddleware # <= 追加
run Rails.application
Rails.application.load_server
以上のように設定して、api側にリクエストしてみると以下のような結果を得られます。
--------------- status ---------------
200
--------------- headers ---------------
{"X-Frame-Options"=>"SAMEORIGIN", "X-XSS-Protection"=>"0", "X-Content-Type-Options"=>"nosniff",
"X-Download-Options"=>"noopen", "X-Permitted-Cross-Domain-Policies"=>"none", "Referrer-Policy"=>"strict-origin-when-cross-origin",
"Content-Type"=>"application/json; charset=utf-8", "ETag"=>"W/\"04feffc04d2090381867383349de9809\"",
"Cache-Control"=>"max-age=0, private, must-revalidate", "X-Request-Id"=>"ecf605ef-ec11-4f73-afa1-49ad20be3820", "X-Runtime"=>"0.045787",
"Server-Timing"=>"start_processing.action_controller;dur=3.481201171875, sql.active_record;dur=11.874755859375, instantiation.active_record;dur=0.32275390625, process_action.action_controller;dur=20.947021484375", "Vary"=>"Origin"}
statusコード
は200
ですが、レスポンスヘッダーに'Access-Control-Allow-Origin'
がないため、ブラウザでは制限されます。
rack-cors
をインストールして、config/initializers/cors.rb
を以下のように設定します。
# Be sure to restart your server when you modify this file.
# Avoid CORS issues when API is called from the frontend app.
# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin AJAX requests.
# Read more: https://github.com/cyu/rack-cors
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins "*"
resource "*",
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
リクエストを送ると以下のような結果が得られます。
--------------- status ---------------
200
--------------- headers ---------------
{"Access-Control-Allow-Origin"=>"*", "Access-Control-Allow-Methods"=>"GET, POST, PUT, PATCH, DELETE, OPTIONS, HEAD",
"Access-Control-Expose-Headers"=>"", "Access-Control-Max-Age"=>"7200", "X-Frame-Options"=>"SAMEORIGIN",
"X-XSS-Protection"=>"0", "X-Content-Type-Options"=>"nosniff", "X-Download-Options"=>"noopen", "X-Permitted-Cross-Domain-Policies"=>"none",
"Referrer-Policy"=>"strict-origin-when-cross-origin", "ETag"=>"W/\"04feffc04d2090381867383349de9809\"", "Cache-Control"=>"max-age=0, private, must-revalidate",
"X-Request-Id"=>"e8085ff2-8ba0-4433-8548-41f1d525afc8", "X-Runtime"=>"0.056507", "Server-Timing"=>"start_processing.action_controller;dur=3.614501953125, sql.active_record;dur=8.42626953125, instantiation.active_record;dur=0.226806640625, process_action.action_controller;dur=16.123779296875", "Vary"=>"Origin"}
Access-Control-Allow-Origin
, Access-Control-Allow-Methods
, Access-Control-Expose-Headers
の3つが新しく追加されています。
"Access-Control-Allow-Origin"=>"*"
は、どのオリジンからのリクエストも許可することを意味しているためブラウザで制限されることはなく正常に動作します。
rack-cors
を導入するとcors.rb
の設定に基づいて、レスポンスヘッダーが変更されることがわかります。
参考にしたサイト