在 Java Play Framework 2.2.x 中启用 CORS

Posted

技术标签:

【中文标题】在 Java Play Framework 2.2.x 中启用 CORS【英文标题】:Enable CORS in Java Play Framework 2.2.x 【发布时间】:2014-04-04 09:13:47 【问题描述】:

我无法在 Java Play 2.2.x 中启用跨域

在 Java Play 2.1.3 中,此代码通过将其放入 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));
  


但是当我尝试在 java play 2.2.x 上编译时,它不再编译了。

编译错误信息:

Global.ActionWrapper 不是抽象的,不会覆盖 Action 中的抽象方法 call(Context) ...

java play 2.2.x 有没有等价的代码?

谢谢。

【问题讨论】:

【参考方案1】:

@alexhanschke 提出的解决方案在请求引发异常(内部服务器错误)时不起作用,因为发生这种情况时不会应用过滤器(请参阅https://github.com/playframework/playframework/issues/2429)。为了解决这个问题,您必须包装一个 scala 类并将其作为结果返回,如下所示。请注意,这仍然需要指定的选项路由和一个控制器来处理选项请求。

在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()));
  


【讨论】:

【参考方案2】:

另一个选项可能是使用Filters。目前只有 Scala 过滤器可用。但是,正如this post 中指出的那样,为了简单地修改响应标头,您可以复制并粘贴以下内容以启用 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 -> "*"))
  

然后将过滤器添加到您的Global.java 中:

@Override
public <T extends EssentialFilter> Class<T>[] filters() 
    return new Class[] EnableCORS.class;

【讨论】:

【参考方案3】:

对于使用 2.3.1+(截至撰写本文时)Play 的任何人,现在是 Promise&lt;Result&gt; 而不是 Promise&lt;SimpleResult&gt;

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));
    

【讨论】:

【参考方案4】:

看起来像这样:

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));
    

【讨论】:

我们使用了这种方法,但遇到了导致错误的请求问题。我们稍微更改了代码,以便在调用委托之前设置响应标头。

以上是关于在 Java Play Framework 2.2.x 中启用 CORS的主要内容,如果未能解决你的问题,请参考以下文章

Play Framework 2.2.2 中的 OAuth

如何在 Play Framework JSON Rest 上使用 java.time.LocalDate?

Play Framework Java - 包 play.db 不存在

缺少包'play.filters.cors.CORSFilter' - Play Framework 2.4.6 (Java)

如何在 java Play Framework 中发送推送通知

无法在 Windows 机器上运行现有的 java Play Framework 项目