Reputation: 158
I'm developing an Angular 2 application on top of a Play Framework 2.5 (Java) back-end. If I access my endpoints through browser URL, they work fine. However, calling it from the Angular 2 application shows the error:
XMLHttpRequest cannot load localhost:9000/app/myendpoint. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'localhost:3000' is therefore not allowed access. The response had HTTP status code 500.
I have tryed to follow the documentation and create the filter:
In application.conf:
play.filters {
cors {
pathPrefixes = ["/app"]
allowedOrigins = null
allowedHttpMethods = null
}
Filter:
import play.mvc.*;
import play.api.http.DefaultHttpFilters; <- error with this import
import play.filters.cors.CORSFilter;
public class Filters extends DefaultHttpFilters {
@Inject public Filters(CORSFilter corsFilter) {
super(corsFilter);
}
}
In build.sbt:
libraryDependencies ++= Seq(
...,
filters
)
Does anyone knows the true solution? Thank you :)
Working code:
Filters.java (on project's root)
import com.google.inject.Inject;
import com.google.inject.Singleton;
import play.http.HttpFilters;
import play.mvc.EssentialAction;
import play.mvc.EssentialFilter;
import play.filters.cors.CORSFilter;
@Singleton
public class Filters extends EssentialFilter implements HttpFilters {
@Inject
private CORSFilter corsFilter;
@Override
public EssentialAction apply(EssentialAction next) {
return corsFilter.asJava().apply(next);
}
@Override
public EssentialFilter[] filters() {
EssentialFilter[] result = new EssentialFilter[1];
result[0] = this;
return result;
}
}
In application.conf:
#filters += Filters <- yes, it is commented since my Filters is in project's root
libraryDependencies += filters
play.filters {
cors{
# allow all paths
pathPrefixes = ["/"]
# allow all origins
allowedOrigins = null
allowedHttpMethods = ["GET", "POST", "PUT", "DELETE"]
# allow all headers
allowedHttpHeaders = null
} ...
In build.sbt:
libraryDependencies ++= Seq(
...,
filters
)
Thank you all! :)
Upvotes: 9
Views: 3296
Reputation: 96
For the sake of others working with Angular 4 front-end and lagom backend project. I have managed to solve this way.
*I added this line below in my build.sbt in both api and impl *
libraryDependencies += filters
In my impl directory, i created folder filters and added the code below
import play.mvc.EssentialFilter;
import play.filters.cors.CORSFilter;
import play.http.HttpFilters;
import javax.inject.Inject;
public class Filters implements HttpFilters {
@Inject
CORSFilter corsFilter;
public EssentialFilter[] filters() {
return new EssentialFilter[]{corsFilter.asJava()};
}
}
In my application.conf i added the code that follows
play.filters.hosts {
# Allow requests to example.com, its subdomains, and localhost:9000.
allowed = ["localhost:5000", "localhost:9000"]
}
play.http.filters = "....filters.Filters"
play.filters.cors {
# Filter paths by a whitelist of path prefixes
pathPrefixes = ["/"]
# The allowed origins. If null, all origins are allowed.
allowedOrigins = null
allowedHttpMethods = ["GET", "POST"]
allowedHttpHeaders = ["Accept"]
preflightMaxAge = 3 days
}
After this, i restarted my lagom microservices and it worked like a charm.
Upvotes: 0
Reputation: 4783
I remember having the same import issue since I think there were some repackaging changes for Filters in Play somewhere around 2.5.0
. And DefaultHttpFilters
was replaced by HttpFilters
during that refactoring.
Check the source code for the correct path to HttpFilters
. Choose the correct tag for the version of Play you are using and then search down the source tree until you find HttpFilters
and check the package. This is the path for the Java API for v 2.5.0.
From your post it seems you are using the Java API but are using the import for the Scala version.
The imports for Play 2.5.0
are:-
Scala - import play.api.http.HttpFilters
Java - import play.http.HttpFilters
I'm using Play 2.5.0
(Scala though - not Java) and this import is working fine for me:-
import play.api.http.HttpFilters
From what you have posted I think you should try changing your problematic import to:-
import play.http.HttpFilters
Also, (as others have stated) I assume you have configured the package for your Filters.java
file if you have not placed it in the root package.
This is the entry in my application.conf
since I am using package filters
rather than the default package.:-
play.http.filters = "filters.Filters"
Upvotes: 1
Reputation: 1963
You do not show much from your project, so it is hard to understand, what a problem it may be. I do not think that there is any CORS issue here, because by default no any security filters are active. You can find here, how you can integrate angular and Play.
Upvotes: 0
Reputation: 837
I think that custom filter solves your problem:
import javax.inject.Inject
import play.api.http.DefaultHttpFilters
import play.filters.cors.CORSFilter
class Filters @Inject() (corsFilter: CORSFilter)
extends DefaultHttpFilters(corsFilter)
and in application.conf
play.http.filters = "filters.MyFilters"
configuration like this:
play.filters.cors {
pathPrefixes = ["/some/path", ...]
allowedOrigins = ["http://www.example.com", ...]
allowedHttpMethods = ["GET", "POST"]
allowedHttpHeaders = ["Accept"]
preflightMaxAge = 3 days
}
Upvotes: 0
Reputation: 10104
If it is only for development purposes you might try with a browser plugin to prevent CORS checks:
For instance, cors everywhere on Firefox or Allow-Control-Allow-Origin in Chrome.
Anyway, in production environment you will have to serve JS assets and services from the same host or set Acces-Control-Allow-Origin header with the specific value for your services.
Upvotes: 0
Reputation: 352
The best practice is to serve both static context and webservice from single origin. For example, for single domain, every URI except /api/* is meant to serve static content and /api/* is a reverse proxy to Java app. You may be specifically interested in Grunt. nginx and Apache could also work.
For example in nginx you specify following configuration:
location /api {
rewrite /api/(.*) /$1 break;
proxy_pass http://127.0.0.1:9000;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
location / {
root /var/www/location;
index index.html index.htm;
}
And then you run your Java app listening on localhost, on port 9000. You are able to copy all your static content to location specified after "root" and get it served by nginx. You send all REST request to /api/method/name
Advantage of this solution is solid security and ability to configure SSL easily.
Upvotes: 3