Enable CORS in Java Play Framework 2.2.x

2019-04-04 06:53发布

I am having trouble of enabling cross domain in Java Play 2.2.x

In Java Play 2.1.3 this code works by putting it in Global.java

public class Global extends GlobalSettings {

  private class ActionWrapper extends Action.Simple {
    public ActionWrapper(Action action) {
     this.delegate = action;
  }

    @Override
    public Result call(Http.Context ctx) throws java.lang.Throwable {
      Result result = this.delegate.call(ctx);
      Http.Response response = ctx.response();
      response.setHeader("Access-Control-Allow-Origin", "*");
      return result;
    }
  }

  @Override
  public Action onRequest(Http.Request request, java.lang.reflect.Method actionMethod) {
    return new ActionWrapper(super.onRequest(request, actionMethod));
  }

}

But when I tried to compile on java play 2.2.x, it does not compile anymore.

The compilation error message:

Global.ActionWrapper is not abstract and does not override abstract method call(Context) in Action ...

Is there any equivalent code for java play 2.2.x?

Thanks.

4条回答
我想做一个坏孩纸
2楼-- · 2019-04-04 07:32

It looks like this:

import play.GlobalSettings;
import play.libs.F.Promise;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.SimpleResult;

public class Global extends GlobalSettings {
    private class ActionWrapper extends Action.Simple {
        public ActionWrapper(Action<?> action) {
            this.delegate = action;
        }

        @Override
        public Promise<SimpleResult> call(Http.Context ctx) throws java.lang.Throwable {
            Promise<SimpleResult> result = this.delegate.call(ctx);
            Http.Response response = ctx.response();
            response.setHeader("Access-Control-Allow-Origin", "*");
            return result;
        }
    }

    @Override
    public Action<?> onRequest(Http.Request request, java.lang.reflect.Method actionMethod) {
        return new ActionWrapper(super.onRequest(request, actionMethod));
    }
}
查看更多
你好瞎i
3楼-- · 2019-04-04 07:35

The solutions proposed by @alexhanschke does not work when the request throws an exception (internal server error), because filters are not applied when that happens (see https://github.com/playframework/playframework/issues/2429). To solve that you have to wrap a scala class and return that as a result, as shown below in full. Please note that this still requires the options route specified and a controller to handle the options request.

See the entire thing here https://gist.github.com/tinusn/38c4c110f7cd1e1ec63f.

import static play.core.j.JavaResults.BadRequest;
import static play.core.j.JavaResults.InternalServerError;
import static play.core.j.JavaResults.NotFound;

import java.util.ArrayList;
import java.util.List;

import play.GlobalSettings;
import play.api.mvc.Results.Status;
import play.libs.F.Promise;
import play.libs.Scala;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;
import scala.Tuple2;
import scala.collection.Seq;

public class Global extends GlobalSettings {

  private class ActionWrapper extends Action.Simple {
    public ActionWrapper(Action<?> action) {
      this.delegate = action;
    }

    @Override
    public Promise<Result> call(Http.Context ctx) throws java.lang.Throwable {
      Promise<Result> result = this.delegate.call(ctx);
      Http.Response response = ctx.response();
      response.setHeader("Access-Control-Allow-Origin", "*");
      return result;
    }
  }

  /*
  * Adds the required CORS header "Access-Control-Allow-Origin" to successfull requests
  */
  @Override
  public Action<?> onRequest(Http.Request request, java.lang.reflect.Method actionMethod) {
    return new ActionWrapper(super.onRequest(request, actionMethod));
  }

  private static class CORSResult implements Result {
    final private play.api.mvc.Result wrappedResult;

    public CORSResult(Status status) {
      List<Tuple2<String, String>> list = new ArrayList<Tuple2<String, String>>();
      Tuple2<String, String> t = new Tuple2<String, String>("Access-Control-Allow-Origin","*");
      list.add(t);
      Seq<Tuple2<String, String>> seq = Scala.toSeq(list);
      wrappedResult = status.withHeaders(seq);
    }

    public play.api.mvc.Result toScala() {
      return this.wrappedResult;
    }
  }

  /*
  * Adds the required CORS header "Access-Control-Allow-Origin" to bad requests
  */
  @Override
  public Promise<Result> onBadRequest(Http.RequestHeader request, String error) {
    return Promise.<Result>pure(new CORSResult(BadRequest()));
  }

  /*
  * Adds the required CORS header "Access-Control-Allow-Origin" to requests that causes an exception
  */
  @Override
  public Promise<Result> onError(Http.RequestHeader request, Throwable t) {
    return Promise.<Result>pure(new CORSResult(InternalServerError()));
  }

  /*
  * Adds the required CORS header "Access-Control-Allow-Origin" when a route was not found
  */
  @Override
  public Promise<Result> onHandlerNotFound(Http.RequestHeader request) {
    return Promise.<Result>pure(new CORSResult(NotFound()));
  }

}
查看更多
三岁会撩人
4楼-- · 2019-04-04 07:39

Another option might be using Filters. Currently there are only Scala filters available. However, as pointed out in this post for the sake of simply modifying the response headers you can copy&paste the following to enable CORS.

package filters

import play.api.mvc._
import play.mvc.Http.HeaderNames
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

class EnableCORS extends Filter {
  def apply(f: (RequestHeader) => Future[Result])(rh: RequestHeader): Future[Result] = {
    val result = f(rh)
    result.map(_.withHeaders(HeaderNames.ACCESS_CONTROL_ALLOW_ORIGIN -> "*"))
  }
}

And then add the filter in your Global.java just so:

@Override
public <T extends EssentialFilter> Class<T>[] filters() {
    return new Class[] {EnableCORS.class};
}
查看更多
Anthone
5楼-- · 2019-04-04 07:41

For anyone using 2.3.1+ (as of this writing) of Play, it's now Promise<Result> instead of Promise<SimpleResult>

import play.GlobalSettings;
import play.libs.F.Promise;
import play.mvc.Action;
import play.mvc.Http;
import play.mvc.Result;

public class Global extends GlobalSettings {
    private class ActionWrapper extends Action.Simple {
        public ActionWrapper(Action<?> action) {
            this.delegate = action;
        }

        @Override
        public Promise<Result> call(Http.Context ctx) throws java.lang.Throwable {
            Promise<Result> result = this.delegate.call(ctx);
            Http.Response response = ctx.response();
            response.setHeader("Access-Control-Allow-Origin", "*");
            return result;
        }
    }

    @Override
    public Action<?> onRequest(Http.Request request, java.lang.reflect.Method actionMethod) {
        return new ActionWrapper(super.onRequest(request, actionMethod));
    }
}
查看更多
登录 后发表回答