I'm currently running a couple of Rails 3.2.x apps. The one using Ruby 1.9.x and is the api endpoint has Rack-cors gem (1.0.1) on it - app Alice; the other runs swagger-ui_rails gem and is the app hosting the api documentation -- app Bob. The swagger docs was created wth swagger-docs gem, which runs format version 1.2. For some reason or another, I cannot get app Alice to give me information for Bob because of this error:
Failed to load https://alice.example.com/api-docs/v1/api-docs.json:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://bob.example.com:3000' is therefore not allowed access.
However! When I look on the network tab, the response is a 200 and I can see the json information. But the response headers definitely do NOT have the required Access-Control-Allow-Origin
header.
This happens both thru AWS Elastic Beanstalk (Bob is hosted on EBS) and locally (w/ a bound address).
In my config/environments/production.rb
of Alice, I have the following:
config.middleware.insert_before 0, 'Rack::Cors' do
allow do
origins ->(origin, env) do
Rails.logger.warn("CORS origin: #{origin}")
origin =~ /\.example\.com(:\d+)?\z/
end
resource('*', :methods => [:get, :post, :options], :headers => :any)
end
end
When I have this code in config/environments/development.rb
in Alice, localhost connects and swagger-ui shows up as expected with no errors in console.
In the network tab of Chrome, this is what I have locally (Bob and Alice in dev/localhost)
Access-Control-Allow-Methods:GET, POST, OPTIONS
Access-Control-Allow-Origin:http://apitest.bob.com:3000
Access-Control-Expose-Headers:
Access-Control-Max-Age:1728000
Content-Length:1499
Content-Type:application/json
Date:Fri, 22 Sep 2017 21:44:45 GMT
Last-Modified:Mon, 28 Aug 2017 17:37:22 GMT
Server:
Vary:Origin
This is what I get for when Bob is in dev and Alice is in prod:
Accept-Ranges:bytes
Connection:keep-alive
Content-Length:1500
Content-Type:application/json
Date:Fri, 22 Sep 2017 23:10:00 GMT
ETag:"abc-559ce64fb8374"
Last-Modified:Fri, 22 Sep 2017 22:04:35 GMT
Server:
As you can see, prod-Alice does not return any sort of headers the way dev-Alice does, even with the exact same Rack-Cors code block.
rake middleware
displays Rack::Cors at the top of the stack, and curl -i https://alice.example.com/api-docs/v1/api-docs.json
has never returned the proper access-control headers for me, both locally and on Bob's server.
prod-Bob also has some EBS extensions to add some request headers and methods to nginx. In some other SO post, I saw folks adding in response headers directly via Rails, and so Bob also has the following in application_controller.rb
(and in dev, with binding.pry, I can confirm that the response definitely has the specified headers)
after_filter :set_access_control_headers
def set_access_control_headers
headers['Access-Control-Allow-Origin'] = Rails.configuration.hostnames['headers']
headers['Access-Control-Request-Methods'] = 'GET, PUT, POST, OPTIONS'
end
I'm a bit at a loss and any help or thoughts would be appreciated.
The Swagger-docs gem that I'm using puts the .json
files that I've created into Rails' /public
directory. As such, Rails sees this as static files and not something that should go through Rack middleware. Since our production.rb file had config.serve_static_assets = false
, that meant that all these static files were the responsibility of our web server (Apache/Nginx) and not the responsibility of rack-cors gem.
After adding in some CORS headers to Apache, swagger-ui loaded appropriately, but was doubling up the headers - 1st for Apache, 2nd for rack-cors.
I've since removed rack-cors gem and have adjusted the Apache server conf setting on Alice, based on an SO answer related to wildcard subdomains:
/etc/apache2/sites-enabled/mysite.conf
SetEnvIf Origin ^(https?://.+\.example\.com(?::\d{1,5})?)$ CORS_ALLOW_ORIGIN=$1
Header append Access-Control-Allow-Origin %{CORS_ALLOW_ORIGIN}e env=CORS_ALLOW_ORIGIN
Header merge Vary "Origin"
Header set "Access-Control-Allow-Methods" "GET, POST, OPTIONS"