我有一个播放2.0.1应用程序,我想使用Javascript托管在其他领域调用。 我的JavaScript调用与失败:
Origin http://mydomain.com is not allowed by Access-Control-Allow-Origin.
我已经发现了一些关于如何设置在播放1正确的HTTP标头的例子,但还没有找到播放2.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服务调用仍然失败。
我需要什么做的就是这个工作?
Answer 1:
只是为了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 =>
???
}
}
Answer 2:
下面是一些背景资料......
- 1)http://www.html5rocks.com/en/tutorials/cors/ - 请注意,你需要阅读一些关于“不那么简单的要求”为JSON属于这一类。
- 2)http://stackoverflow.com/questions/9613210/cors-access-control-allow-origin-despite-correct-headers?rq=1
- 3)http://caniuse.com/#search=cors - 详细的浏览器支持CORS
- 4)http://stackoverflow.com/questions/10748537/access-control-allow-origin-on-playframework(用于播放1 NOT播放2)
所以这是我实现的:
由于不那么简单的要求(见上文1)进行飞行前的通话,则需要以下内容添加到路由文件:
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结果(如上面我的问题)控制器方法的结尾:
public static Result myJsonWebService() {
...
response().setHeader("Access-Control-Allow-Origin", "*");
return ok(toJson(jsonObject));
}
Answer 3:
这样做的一个很好的方式是通过扩展操作:
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()请求将上述标题回应。
Answer 4:
实现为斯卡拉过滤器(播放的2.2.x):
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) {...}
文章来源: Play 2.0.1 and setting Access-Control-Allow-Origin