Javascript 播放2.0.1并设置访问控制允许原点

Javascript 播放2.0.1并设置访问控制允许原点,javascript,http-headers,xmlhttprequest,playframework-2.0,Javascript,Http Headers,Xmlhttprequest,Playframework 2.0,我有一个Play2.0.1应用程序,我想使用托管在其他域上的Javascript调用它。我的Javascript调用失败,原因是: Origin http://mydomain.com is not allowed by Access-Control-Allow-Origin. 我在Play1中找到了许多关于如何设置正确HTTP头的示例,但在Play2.0.1中没有找到任何示例。阅读文档之后(http://www.playframework.org/documentation/2.0.2/Ja

我有一个Play2.0.1应用程序,我想使用托管在其他域上的Javascript调用它。我的Javascript调用失败,原因是:

Origin http://mydomain.com is not allowed by Access-Control-Allow-Origin.
我在Play1中找到了许多关于如何设置正确HTTP头的示例,但在Play2.0.1中没有找到任何示例。阅读文档之后(http://www.playframework.org/documentation/2.0.2/JavaResponse)为了让事情顺利进行,我尝试了以下方法:

public static Result myJsonWebService() {
  ...
  response().setHeader("Access-Control-Allow-Origin", "*");
  return ok(toJson(jsonObject));
}
但是我的JS web服务调用仍然失败


我需要做些什么才能让它工作?

这里是一些背景信息

  • (一)http://www.html5rocks.com/en/tutorials/cors/ -注意,您需要阅读关于“不那么简单的请求”的部分,因为JSon属于这一类
  • (二)http://stackoverflow.com/questions/9613210/cors-access-control-allow-origin-despite-correct-headers?rq=1
  • (三)http://caniuse.com/#search=cors -详细说明支持CORS的浏览器
  • (四)http://stackoverflow.com/questions/10748537/access-control-allow-origin-on-playframework (用于播放1而不是播放2)
下面是我实现的:

由于并非如此简单的请求(见上文1)会发出飞行前呼叫,您需要将以下内容添加到routes文件中:

POST /url_to_json_webservice        controllers.myJsonWebServices.myJsonWebService
OPTIONS /url_to_json_webservice     controllers.myJsonWebServices.checkPreFlight
然后在控制器中设置以下方法:

public static Result checkPreFlight() {
    response().setHeader("Access-Control-Allow-Origin", "*");       // Need to add the correct domain in here!!
    response().setHeader("Access-Control-Allow-Methods", "POST");   // Only allow POST
    response().setHeader("Access-Control-Max-Age", "300");          // Cache response for 5 minutes
    response().setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");         // Ensure this header is also allowed!  
    return ok();
}
注意,我可能在这里设置了比需要更多的标题,所以请检查您需要的标题

还记得在返回实际JSon结果的控制器方法末尾添加以下内容(如我上面的问题所述):


一种很好的方法是扩展操作:

package actions;

import play.*;
import play.mvc.*;
import play.mvc.Http.Context;
import play.mvc.Http.Response;

public class CorsAction extends Action.Simple {

public Result call(Context context) throws Throwable{
    Response response = context.response();
    response.setHeader("Access-Control-Allow-Origin", "*");

    //Handle preflight requests
    if(context.request().method().equals("OPTIONS")) {
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Auth-Token");
        response.setHeader("Access-Control-Allow-Credentials", "true");

        return ok();
    }

    response.setHeader("Access-Control-Allow-Headers","X-Requested-With, Content-Type, X-Auth-Token");
    return delegate.call(context);
}

}
然后在控制器中添加以下行:

@With(CorsAction.class)

然后,所有ok()请求都将使用上述标题进行响应。

仅针对Scala人员,这是我当前使用的实现:

import play.api.mvc._
import scala.concurrent._
import play.api.http.HeaderNames._

/**
 * Action decorator that provide CORS support
 *
 * @author Giovanni Costagliola, Nick McCready
 */
case class WithCors(httpVerbs: String*)(action: EssentialAction) extends EssentialAction with Results {
    def apply(request: RequestHeader) = {
        implicit val executionContext: ExecutionContext = play.api.libs.concurrent.Execution.defaultContext
        val origin = request.headers.get(ORIGIN).getOrElse("*")
        if (request.method == "OPTIONS") { // preflight
            val corsAction = Action {
                request =>
                    Ok("").withHeaders(
                        ACCESS_CONTROL_ALLOW_ORIGIN -> origin,
                        ACCESS_CONTROL_ALLOW_METHODS -> (httpVerbs.toSet + "OPTIONS").mkString(", "),
                        ACCESS_CONTROL_MAX_AGE -> "3600",
                        ACCESS_CONTROL_ALLOW_HEADERS ->  s"$ORIGIN, X-Requested-With, $CONTENT_TYPE, $ACCEPT, $AUTHORIZATION, X-Auth-Token",
                        ACCESS_CONTROL_ALLOW_CREDENTIALS -> "true")
            }
            corsAction(request)
        } else { // actual request
            action(request).map(res => res.withHeaders(
                ACCESS_CONTROL_ALLOW_ORIGIN -> origin,
                ACCESS_CONTROL_ALLOW_CREDENTIALS -> "true"
            ))
        }
    }
}
要使用它,只需通过以下方式装饰您的行为:

def myAction = WithCors("GET", "POST") {
  Action { request =>
    ???
  }
}

作为Scala过滤器实现(play 2.2.x):


我想在你的网站上改进你的答案。但是我不能登录。谢谢尼克,我已经集成了你的改进
def myAction = WithCors("GET", "POST") {
  Action { request =>
    ???
  }
}
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.mvc._
import play.api.mvc.Results._
import play.api.http.HeaderNames._

object Cors extends Filter {
  def apply(next: (RequestHeader) => Future[SimpleResult])(request: RequestHeader): Future[SimpleResult] = {
    val origin = request.headers.get(ORIGIN).getOrElse("*")
    if (request.method == "OPTIONS") {
      val response = Ok.withHeaders(
        ACCESS_CONTROL_ALLOW_ORIGIN -> origin,
        ACCESS_CONTROL_ALLOW_METHODS -> "POST, GET, OPTIONS, PUT, DELETE",
        ACCESS_CONTROL_MAX_AGE -> "3600",
        ACCESS_CONTROL_ALLOW_HEADERS -> s"$ORIGIN, X-Requested-With, $CONTENT_TYPE, $ACCEPT, $AUTHORIZATION, X-Auth-Token",
        ACCESS_CONTROL_ALLOW_CREDENTIALS -> "true"
      )
      Future.successful(response)
    } else {
      next(request).map {
        res => res.withHeaders(
          ACCESS_CONTROL_ALLOW_ORIGIN -> origin,
          ACCESS_CONTROL_ALLOW_CREDENTIALS -> "true"
        )
      }
    }
  }
}

object Global extends WithFilters(Cors) {...}