###Enabling CORS for a PredictionIO Engine This guide is meant for people who have no experience with nginx and want to enable Cross-Origin Resource Sharing (CORS) with their predictionIO instance. Enabling CORS is needed if you'd like to query your engine from anther domain's front end.
In my case, I had the recommender engine running on an aws instance. My goal was to query with AJAX from another domain. For example:
data = {'user': 'Bob', 'num': 4};
$.ajax({
url: 'http://<pio ip>:8000/queries.json',
type: 'POST',
data: JSON.stringify(data),
header: {
'Content-Type': 'application/json'
},
complete: function (response) {
console.log(response.responseText);
}
});
Without some extra work however, this request returns an error
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://<pio ip>:8000/queries.json. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
The workaround to this is to use an nginx proxy. As stated on the pio github cors issue, essentially putting a man in the middle that allows CORS. Nginx will take the cross-domain queries and modify them before sending them on to the engine. This can all be done on a single server.
#####Prerequisites
-
build, train, and deploy your predictionIO engine on your AWS instance. After deploying, navigate to http://<pio ip>:8000 in your browser and you should an engine status page. If you want to be sure that queries will work, you can do a curl request from your local machine
curl -H "Content-Type: application/json" -d '{ "user": "Bob", "num": 4 }' http://<pio ip>:8000/queries.json
-
Authorize traffic on a new port, I used 8082
-
Install nginx on your predictionIO engine server (
sudo apt-get install nginx
)
#####Configure nginx Now we need to configure nginx to listen on port 8082, grab the requests, add the CORS-enabling headers, and forward it to your engine at port 8000.
Open up /etc/nginx/nginx.conf with your favorite editor and replace what is in there with the following:
#System configuration ##################
worker_processes 3;
events {
worker_connections 1024;
}
# Web configuration #####################
http {
server {
listen 8082 default;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
proxy_pass http://[::1]:8000;
}
}
}
The particularly tricky part here was that the predictionIO engine is listening on IPv6, so you need to pass to http://[::1]:8000
rather than http://127.0.0.1:8000;
.
#####Start it all up
Make sure your engine is still running at http://<pio ip>:8000. Then restart nginx with sudo service nginx restart
. Whenever you make changes to nginx.conf you need to restart to apply them. Once nginx is running, go to http://<pio ip>:8082 and you should see the same engine status page.
If that's all working, you can now do cross-origin requests. The query from the introduction just needs to be modified with the new port number as such:
data = {'user': 'Bob', 'num': 4};
$.ajax({
url: 'http://<pio ip>:8082/queries.json',
type: 'POST',
data: JSON.stringify(data),
header: {
'Content-Type': 'application/json'
},
complete: function (response) {
console.log(response.responseText);
}
});
That should do the trick! Now you'll get back a nice json response
{"itemScores":[{"item":"1","score":1.29},{"item":"2","score":1.27},{"item":"3","score":1.21},{"item":"4","score":1.14}]}
Excellent guide! On CentOS I also had to run the commands below.
And update /etc/nginx/nginx.conf to accept $request_method = 'OPTIONS' and proxy the PIO event server on port 7070.