【问题标题】:Play 2.0.1 and setting Access-Control-Allow-Origin播放 2.0.1 并设置 Access-Control-Allow-Origin
【发布时间】:2013-01-04 00:06:55
【问题描述】:

我有一个 Play 2.0.1 应用程序,我想使用托管在其他域上的 Javascript 来调用它。我的 Javascript 调用失败:

Origin http://mydomain.com is not allowed by Access-Control-Allow-Origin.

我找到了一些关于如何在 Play 1 中设置正确的 HTTP 标头的示例,但没有找到适用于 Play 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 网络服务调用仍然失败。

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

【问题讨论】:

    标签: javascript http-headers xmlhttprequest playframework-2.0


    【解决方案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 =>
        ???
      }
    }
    

    【讨论】:

    • 我想改进您在您网站上的回答。但我无法登录。
    • 谢谢尼克,我已经整合了你的改进
    【解决方案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(适用于 Play 1 NOT Play 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));
    }
    

    【讨论】:

      【解决方案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() 请求都会响应上面的 headers。

      【讨论】:

        【解决方案4】:

        实现为 Scala 过滤器(播放 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) {...}
        

        【讨论】:

          猜你喜欢
          • 2017-07-31
          • 2016-07-21
          • 1970-01-01
          • 1970-01-01
          • 2011-04-06
          • 2018-01-24
          • 2015-10-29
          • 2021-01-01
          • 1970-01-01
          相关资源
          最近更新 更多