Определить Акка HttpRequest и HttpResponse? - PullRequest
0 голосов
/ 28 мая 2018

Во время использования Akka HttpRequest и передачи запроса актеру, я не смог определить ответ.Актер будет обрабатывать каждое полученное сообщение, но не знает, какой запрос использовался для получения этого ответа.Есть ли способ идентифицировать каждый запрос на совпадение с ответом?

Примечание. У меня нет сервера для повторной отправки какой-либо части тела запроса.

Заранее спасибо

MySelf.scala

import akka.actor.{ Actor, ActorLogging }
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.stream.{ ActorMaterializer, ActorMaterializerSettings }
import akka.util.ByteString

class Myself extends Actor with ActorLogging {

import akka.pattern.pipe
import context.dispatcher

final implicit val materializer: ActorMaterializer = 
       ActorMaterializer(ActorMaterializerSettings(context.system))

def receive = {
  case HttpResponse(StatusCodes.OK, headers, entity, _) =>
    entity.dataBytes.runFold(ByteString(""))(_ ++ _).foreach { body =>
      log.info("Got response, body: " + body.utf8String)
  }
  case resp @ HttpResponse(code, _, _, _) =>
    log.info("Request failed, response code: " + code)
    resp.discardEntityBytes()
  }

}

Main.scala

import akka.actor.{ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.stream.ActorMaterializer

object HttpServerMain extends App {

import akka.pattern.pipe

//  import system.dispatcher
implicit val system = ActorSystem()
implicit val materializer = ActorMaterializer()
// needed for the future flatMap/onComplete in the end
implicit val executionContext = system.dispatcher

val http = Http(system)

val myActor = system.actorOf(Props[MySelf])

http.singleRequest(HttpRequest(uri = "http://akka.io"))
    .pipeTo(myActor)

http.singleRequest(HttpRequest(uri = "http://akka.io/another-request"))
    .pipeTo(myActor)
Thread.sleep(2000)
system.terminate()

Ответы [ 2 ]

0 голосов
/ 28 мая 2018

Я думаю, что вы не можете сделать это напрямую, используя pipeTo, потому что это просто добавляет andThen вызов к вашему Future.Один из вариантов - map, а затем отправить (request, response) кортеж актеру:

val request = HttpRequest(uri = "http://akka.io")
http.singleRequest(request).map {
  response => myActor ! (request, response)
}

class Myself extends Actor with ActorLogging {
  ...
  def receive = {
    case (request, HttpResponse(StatusCodes.OK, headers, entity, _)) =>
      ...

    case (request, resp @ HttpResponse(code, _, _, _)) =>
      log.info(request.toString)
      ...
  }
}
0 голосов
/ 28 мая 2018

Вы можете просто использовать map для преобразования Future и добавить какой-либо идентификатор (обычно называемый идентификатором корреляции для таких целей) перед тем, как передать его на myActor:

http.singleRequest(HttpRequest(uri = "http://akka.io"))
    .map(x => (1, x)).pipeTo(myActor)

Вам понадобится изменить блоки сопоставления с образцом, чтобы взять набор:

case (id, HttpResponse(StatusCodes.OK, headers, entity, _)) =>

Если вы не можете / не хотите менять блок сопоставления с образцом по какой-то причине, вы можете использовать тот же подход,но вместо этого добавьте уникальный HTTP-заголовок в ваш завершенный запрос (используя copy) с чем-то вроде этого (не проверяется, если компилируется):

// make a unique header name that you are sure will not be
// received from http response:
val correlationHeader: HttpHeader = ... // mycustomheader

// Basically hack the response to add your header:
http.singleRequest(HttpRequest(uri = "http://akka.io"))
    .map(x => x.copy(headers = correlationHeader +: headers)).pipeTo(myActor)

// Now you can check your header to see which response that was:
case HttpResponse(StatusCodes.OK, headers, entity, _) =>
  headers.find(_.is("mycustomheader")).map(_.value).getOrElse("NA")

Это скорее хак, по сравнению с предыдущим вариантом, потому что выизменяют ответ.

...