2013-01-20 11 views
13

Ho un'applicazione Play 2.0.1 che desidero chiamare utilizzando Javascript ospitato su altri domini. La mia chiamata Javascript sta venendo a mancare con:Play 2.0.1 e impostazione Access-Control-Allow-Origin

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

ho trovato una serie di esempi di come impostare l'header HTTP corretto in Play 1, ma non ho trovato nulla for Gioca 2.0.1. Dopo aver letto la documentazione (http://www.playframework.org/documentation/2.0.2/JavaResponse) ho provato la seguente solo per ottenere le cose di lavoro:

public static Result myJsonWebService() { 
    ... 
    response().setHeader("Access-Control-Allow-Origin", "*"); 
    return ok(toJson(jsonObject)); 
} 

ma la mia chiamata di servizio Web JS è ancora fallendo.

Cosa devo fare per farlo funzionare?

risposta

11

Ecco alcune informazioni di base ...

  • 1) http://www.html5rocks.com/en/tutorials/cors/ - Si noti che è necessario leggere il bit di "non è così semplice richiede "come JSon rientra in questa categoria.
  • 2) http://stackoverflow.com/questions//cors-access-control-allow-origin-despite-correct-headers?rq=1
  • 3) http://caniuse.com/# search = cors - Dettagli browser che supportano CORS
  • 4) http://stackoverflow.com/questions/10748537/access-control-allow-origin-on-playframework (for Gioca 1 NON Play 2)

Quindi ecco cosa ho implementato:

Come richieste non-così-semplici (vedere 1 sopra) effettuare una chiamata pre-volo, è necessario aggiungere il seguente al file di percorsi:

POST /url_to_json_webservice  controllers.myJsonWebServices.myJsonWebService 
OPTIONS /url_to_json_webservice  controllers.myJsonWebServices.checkPreFlight 

e quindi impostare il seguente metodo nel controller:

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

Nota forse ho impostato più intestazioni del necessario qui, quindi si prega di controllare quali avete bisogno !!

anche ricordarsi di aggiungere il seguente alla fine del tuo metodo di controllo che restituisce il risultato in realtà JSON (come nel mio domanda di cui sopra):

public static Result myJsonWebService() { 
    ... 
    response().setHeader("Access-Control-Allow-Origin", "*"); 
    return ok(toJson(jsonObject)); 
} 
3

Un bel modo per farlo è quello di estendere le azioni:

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

} 

Poi nel controller di aggiungere questa riga:

@With(CorsAction.class) 

Poi un Le richieste ok() risponderanno con le intestazioni sopra.

14

solo per i ragazzi Scala, questo è l'implementazione Attualmente sto usando:

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" 
      )) 
     } 
    } 
} 

Per usarlo basta decorare la vostra azione nel modo seguente:

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

Volevo migliorare la risposta sul tuo sito web. Ma non riesco ad accedere. – Nick

+1

Grazie Nick, ho integrato i tuoi miglioramenti –

1

implementato come filtro Scala (riproduzione 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) {...} 
Problemi correlati