Akka HTTP "actor per request"模式



目前我正在尝试在AkkaHTTP中实现NET-A-PORTER开发人员提出的"每个请求的参与者"模式。我面临的问题是,文档中没有记录这种模式。似乎没有办法做到以下几点:

IO(Http) ! Http.Bind(serviceActor, "localhost", port = 38080)

在不使用Spray的情况下,如何根据请求使用一个Akka演员?

HttpExt类有一个可用于此目的的方法bindAndHAndleAsync。此方法接收具有以下签名的函数:

handler: (HttpRequest) ⇒ Future[HttpResponse]

因此,假设我们有一个Actor,当被问及HttpRequest:时,他会产生HttpResponse

class HttpResponseHandlerActor extends Actor {
  override def receive = {
    case _ : HttpRequest => 
      sender() ! HttpResponse(200, entity = "Response From Actor")
  }
}

低效回答

您的问题明确询问如何在每个请求中使用1个Actor,为此,我们现在可以使用Actor类来创建一个处理程序函数:

implicit val actorSystem = ActorSystem()
implicit val timeout = Timeout(5 seconds)
val handler : (HttpRequest) => Future[HttpResponse] = (httpRequest) = {
  val actorHandlerRef = 
    system.actorOf(Props[HttpResponseHandlerActor], "responseActor")
  (actorHandlerRef ask httpRequest).mapTo[HttpResponse]
}

我们现在可以使用此功能将我们的服务器绑定到:

val serverBinding : Future[ServerBinding] = 
  Http().bindAndHandleAsync(handler, "localhost", 8080)

高效应答

通常不需要为每个请求重新创建一个新的Actor,通常您希望创建一个Actor并将其用于每个请求
因此,我们可以将Actor创作转移到handler:之外

val handler : (ActorRef) => (HttpRequest) => Future[HttpResponse] = 
  (actorRef) => (httpRequest) =>
     (actorRef ask httpRequest).mapTo[HttpResponse]

服务器绑定现在稍微修改为:

val singleResponseActorRef = 
  system.actorOf(Props[HttpResponseHandlerActor], "responseActor")
val serverBinding : Future[ServerBinding] = 
  Http().bindAndHandleAsync(handler(singleResponseActorRef),
                            "localhost", 
                            8080)

最新更新