2015-06-19 13 views
5

Stiamo utilizzando l'API Java Akka-HTTP, utilizzando il routing DSL.Come rispondere al risultato di una chiamata di un attore?

Non è chiaro come utilizzare la funzionalità di routing per rispondere a una richiesta HttpRequest; usando un attore Akka non tipizzato. Ad esempio, quando si abbina un percorso di instradamento, come si trasferisce la richiesta ad un "gestore" ActorRef, che risponderà quindi con un HttpResponse in modo asincrono?

Una domanda simile è stata pubblicata sulla mailing list di Akka-User, ma senza soluzioni di follow-up in quanto tale - https://groups.google.com/d/msg/akka-user/qHe3Ko7EVvg/KC-aKz_o5aoJ.

risposta

5

Ciò può essere ottenuto con una combinazione della direttiva onComplete e del modello ask.

Nell'esempio seguente l'attore RequestHandlerActor viene utilizzato per creare uno HttpResponse basato su HttpRequest. Questo attore viene invitato dall'interno del percorso.

Non ho mai usato Java per il codice di routing, quindi la mia risposta è in Scala.

import scala.concurrent.duration._ 
import akka.actor.ActorSystem 
import akka.http.scaladsl.model.HttpResponse 
import akka.http.scaladsl.model.HttpRequest 
import akka.actor.Actor 
import akka.http.scaladsl.server.Directives._ 
import akka.actor.Props 
import akka.pattern.ask 
import akka.util.Timeout 
import scala.util.{Success, Failure} 
import akka.http.scaladsl.model.StatusCodes.InternalServerError 

class RequestHandlerActor extends Actor { 
    override def receive = { 
    case httpRequest : HttpRequest => 
     sender() ! HttpResponse(entity = "actor responds nicely") 
    } 
} 

implicit val actorSystem = ActorSystem() 
implicit val timeout = Timeout(5 seconds) 

val requestRef = actorSystem actorOf Props[RequestHandlerActor] 

val route = 
    extractRequest { request => 
    onComplete((requestRef ? request).mapTo[HttpResponse]) { 
     case Success(response) => complete(response) 
     case Failure(ex) => 
     complete((InternalServerError, s"Actor not playing nice: ${ex.getMessage}")) 
    } 
    } 

Questo percorso può quindi essere utilizzata passato nel metodo bindAndHandle come qualsiasi altro flusso.

1

Ho cercato la soluzione allo stesso problema descritto dall'autore della domanda. Infine, mi si avvicinò al seguente codice Java per la creazione di rotta:

ActorRef ref = system.actorOf(Props.create(RequestHandlerActor.class)); 

    return get(() -> route(
      pathSingleSlash(() -> 
        extractRequest(httpRequest -> { 
         Timeout timeout = new Timeout(Duration.create(5, TimeUnit.SECONDS)); 
         CompletionStage<HttpResponse> completionStage = PatternsCS.ask(ref, httpRequest, timeout) 
           .thenApplyAsync(HttpResponse.class::cast); 

         return completeWithFuture(completionStage); 
        }) 
      )) 
    ); 

E RequestHandlerActor è:

public class RequestHandlerActor extends UntypedActor { 
    @Override 
    public void onReceive(Object msg) { 
     if (msg instanceof HttpRequest) { 
      HttpResponse httpResponse = HttpResponse.create() 
        .withEntity(ContentTypes.TEXT_HTML_UTF8, 
          "<html><body>Hello world!</body></html>"); 

      getSender().tell(httpResponse, getSelf()); 
     } else { 
      unhandled(msg); 
     } 
    } 
} 
Problemi correlati