2016-04-06 3 views
1

Я работаю с Akka HTTP, и у меня есть клиент, который запрашивает URL-адрес. Код что-то вроде этого:Akka-http и преобразование Future [HttpResponse] в будущее [String]

def f1(): Future[HttpResponse] = { ... } 

Я хочу написать f2 функцию, которая принимает HttpRespons е, но превращает его в Future[String] где String есть тело сообщения. Я ищу:

def f2(): Future[String] = f1().map(...) 

Мне не удалось это скорректировать, чтобы правильно работать.

Вопрос №1: Я думаю, что это более важный вопрос Скалы. Как я буду преобразовывать это будущее? Лучшее, что я могу получить это:

def f2:Future[String] = { 
f1().map (_.entity.toStrict(300.milli).map(_.data.utf8String)) 
} 

, который не работает, так как я в конечном итоге с Future[Future[String]]

Вопрос # 2: Это Акка-клиента вопрос для моего понимания.

f1().map(_.toStrict()) imply f1().map(_.entity.toStrict())?

Если да, то каким образом я могу получить доступ к объекту без необходимости также называть toStrict?

+1

Используйте 'flatMap' вместо' map', когда результат функции, переданной 'map', возвращает' Future'. –

+0

Не могли бы вы объяснить, почему вы хотите преобразовать его в String и для чего вы его будете использовать? –

ответ

2

// 1. Вы можете использовать для понимания (с опцией [Option [T]], Future [Future [T]], Try [Try [T]) или flatMap или .map {_ pipeTo self} (если в актере).

val httpResponseF: Future[HttpResponse] = Future.successful(HttpResponse(entity = HttpEntity.Strict(ContentTypes.`text/plain(UTF-8)`, data = ByteString("test")))) 
val res: Future[String] = for { 
    httpResponse <- httpResponseF 
    entity  <- httpResponse.entity.toStrict(300.milli) 
} yield { 
    entity match { 
    case HttpEntity.Strict(contentType, data) => data.utf8String 
    } 
} 
assert(Await.result(res, 1.second) == "test") 

// 2. Они выглядят по-разному для меня: akka.http.scaladsl.model.HttpResponse

def 
toStrict(timeout: FiniteDuration)(implicit ec: ExecutionContext, fm: Materializer): Future[Self] 

против

//akka.http.javadsl.model.ResponseEntity

def 
toStrict(timeoutMillis: Long, materializer: Materializer): CompletionStage[HttpEntity.Strict] 

Один использует неявки.

Вот один из способов получить строку в качестве http-клиента.

object Example { 
    import scala.concurrent.Future 
    import akka.actor.ActorSystem 
    import akka.http.scaladsl.Http 
    import akka.stream.ActorMaterializer 
    import akka.stream.scaladsl.Sink 
    import akka.stream.scaladsl.Source 
    import akka.http.scaladsl.unmarshalling._ 
    import akka.http.scaladsl.model._ 
    import scala.util.{Try,Success,Failure} 
    implicit val system = ActorSystem() 
    implicit val materializer = ActorMaterializer() 
    implicit val ec = system.dispatcher 
    // construct a pool client flow with context type `Int` 
    val poolClientFlow = Http().cachedHostConnectionPool[Int]("akka.io") 
    val responseFuture: Future[String] = 
    Source.single(HttpRequest(uri = "/") -> 1) 
     .via(poolClientFlow) 
     .mapAsync(1) { 
      case (Success(response), i) => Unmarshal(response.entity).to[String] 
      case (Failure(e), i)  => Future.failed(e) 
     } 
     .runWith(Sink.head) 

} 

Если существует более конкретный тип (более идиоматических при использовании Scala) вы пытаетесь маршализацию до, а не строки, вы можете создать собственный Unmarshaller с помощью этого JSon в качестве шаблона: https://github.com/hseeberger/akka-http-json/blob/master/akka-http-json4s/src/main/scala/de/heikoseeberger/akkahttpjson4s/Json4sSupport.scala иначе есть Unmarshallers. String http://doc.akka.io/docs/akka/2.4.3/java/http/routing-dsl/marshalling.html#Unmarshalling

Иногда проверка списка рассылок Spray и документов помогает, так как он активен дольше, даже если есть новый способ сделать это в akka-http, по крайней мере, является отправной точкой.

+0

Спасибо, сэм. Я немного смущен, для понимания получается будущее [HttpEntity.Strict], а не будущее [String]? –

+0

@WillIAm обновлен для преобразования в строку. Извините, тестировал пример в конце, но не первый. – sam

0

Вы можете написать f2() как таковой.

def f2[T] = f1.mapTo[T] 
0

Для Q1:

Если вы получаете Future[Future[_]], где вам нужно Future[_], вы должны заменить map с flatMap. То же самое относится к Option и коллекциям.

Так это выглядит правильно:

def f2(): Future[String] = { 
f1().flatMap (_.entity.toStrict(300.milli).map(_.data.utf8String)) 
} 

Для Q2:

HttpMessage.toStrict заколлирует HttpEntity.toStrict внутренне поэтому они делают то же самое. (Обратите внимание, что по какой-либо причине HttpMessage.toStrict не отображается в интерфейсе Java).

Смежные вопросы