I am developing an AngularJS application calling a REST API developed with Play Framework 2.2.0.
I have a problem related to Cross-domain ajax calls as the Angular application and the Play one will not be hosted on the same domain.
Here is the JS call in my Angular service :
$http
.post("http://localhost:9001/category/list", { langCode: 'fr-FR' })
.success(function(data, status, headers, config) {
callback(data.items);
})
.error(function(data, status, headers, config) {
console.log("Error Data : " + data);
console.log("Error Status : " + status);
});
Here is the route in my Play app :
POST /category/list controllers.catalog.ProductCategoryController.list()
- If I don't send any data in the request, everything works fine
- If I send data, I have Ajax errors concerning ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_ALLOW_HEADERS
The only workaround I have is the following :
Intercept all requests in Global class and add the headers
@Override public Action onRequest(Request request, Method method) { return new Action.Simple() { @Override public Promise<SimpleResult> call(Context ctx) throws Throwable { Logger.debug("Intercepting request and applying CORS headers..."); ctx.response().setHeader(Controller.ACCESS_CONTROL_ALLOW_ORIGIN, "*"); ctx.response().setHeader(Controller.ACCESS_CONTROL_ALLOW_HEADERS, "Content-Type"); return delegate.call(ctx); } }; }
Add another route with OPTIONS in routes
OPTIONS /category/list controllers.catalog.ProductCategoryController.list()
Is there a way of making the integration simpler than that ?
You have to enable CORS support to your Play web server. The following url do have plenty of how-to for configurating server enabling the cross origin support:
http://enable-cors.org/server.html
There's no CORS support out of the box in play; that's a situation I'd like to see changed, but for now you've identified a wart.
The good news is that you can manage a global workaround if you are OK having one CORS setting for all of your resources. It can be done in a couple of ways, one of which you identified. My inclination would be to go with a low level OPTIONS route.
Something like:
From there, your handler definition can be something like:
It's not super clean, but until Play adds something a bit more workable, I think it's your best option over making tons of OPTIONS routes (again, assuming you're comfortable with a global CORS setting)