Reputation: 2737
I have a Rails3 app hosted via NginX which provides a JSON API that shall support cross origin resource sharing (CORS). The related headers should be added via NginX, not via the Rails app.
Therefore I added a catcher in routes.rb to fetch OPTIONS preflight requests:
match "*options", controller: "application", action: "options", constraints: { method: "OPTIONS" }
and I added the corresponding endpoint to my application controller:
def options
render :text => "", :layout => false
end
Works. Now I want a wide open CORS config for my NginX:
server {
listen 80;
server_name localhost;
passenger_enabled on;
root /home/deployer/apps/fooapp/current/public;
location /v1 {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-FooApp-Auth-Token';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 200;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-FooApp-Auth-Token';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-FooApp-Auth-Token';
}
}
}
Great, OPTIONS request have all the needed headers in the response now:
curl -i -H'Accept: application/json' -H'Content-Type: application/json' -XOPTIONS 'http://api.fooapp.net/v1/api_session' -d'{"user":{"email":"[email protected]", "password":"somepassword"}}'
HTTP/1.1 200 OK
Server: nginx/1.2.3
Date: Sun, 02 Sep 2012 11:04:28 GMT
Content-Type: application/octet-stream
Content-Length: 0
Connection: keep-alive
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,X-FooApp-Auth-Token
Access-Control-Max-Age: 1728000
Content-Type: text/plain charset=UTF-8
Content-Length: 0
But a real POST requests for example now fails with a 404:
curl -i -H'Accept: application/json' -H'Content-Type: application/json' -XPOST 'http://api.fooapp.net/v1/api_session' -d'{"user":{"email":"[email protected]", "password":"somepassword"}}'
HTTP/1.1 404 Not Found
Server: nginx/1.2.3
Date: Sun, 02 Sep 2012 11:06:19 GMT
Content-Type: text/html
Content-Length: 168
Connection: keep-alive
<html>
<head><title>404 Not Found</title></head>
<body bgcolor="white">
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.2.3</center>
</body>
</html>
And it has to, cause the NginX log says:
2012/09/02 13:06:19 [error] 2464#0: *3 open() "/home/deployer/apps/fooapp/current/public/v1/api_session" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "POST /v1/api_session HTTP/1.1", host: "api.fooapp.net"
I am new to NginX, and I know thats a wide open as well as very lightweight configuration. I do not understand why NginX tries to route these requests via public, so that the underlying Rails app is not requested. How do I have to change the configuration, so that all my requests are passed to the app as before, but the CORS headers are added anyway?
Thx in advance
Felix
Upvotes: 3
Views: 2349
Reputation: 46
This comes a little late but since I just ran into the same problem it might help somebody else.
You need to enable passenger inside the location block
location /{
...
passenger_enabled on;
...
}
I hope this helps.
Upvotes: 2