Play2-mini и Akka2 для HTTP-шлюза

Я оцениваю возможность использования Play2-mini со Scala для разработки службы, которая будет располагаться между мобильным клиентом и существующими веб-сервис. Я ищу самый простой пример кода, где Play2-mini реализует сервер и клиент. В идеале клиент будет использовать актеров Akka2.

С этим вопросом я пытаюсь выяснить, как это делается, а также посмотреть, как Play2-Mini и Akka2 должны взаимодействовать. Поскольку Play2-Mini, по-видимому, является заменой HTTP-модулей Akka.

Play2-mini содержит следующий пример кода, в котором я создал два TODO. Если кто-то может помочь мне с примером кода для начала, я буду очень благодарен.

package com.example

import com.typesafe.play.mini._
import play.api.mvc._
import play.api.mvc.Results._

object App extends Application {
  def route = {
    case GET(Path("/testservice")) & QueryString(qs) => Action{ request=>
      println(request.body)
      //TODO Take parameter and content from the request them pass it to the back-end server
      //TODO Receive a response from the back-end server and pass it back as a response
      Ok(<h1>Server response: String {result}</h1>).as("text/html")
    }
  }
}

person Jack    schedule 13.02.2012    source источник
comment
Дайте мне знать, если мой ответ не соответствует вашим ожиданиям и нуждается в некоторых изменениях. Или поясните, если я упустил момент. Возможно, вы подумали, что вам нужно явно использовать актеров для вашего HTTP-шлюза, но это не так. Самый простой способ — использовать Async и play.api.libs.ws.WS и позволить платформе Play управлять актерами Akka.   -  person romusz    schedule 13.03.2012
comment
Спасибо за дружескую помощь @romusz. Ответ выглядит идеально ;-), но у меня не было возможности реализовать его на своем сервере, поэтому мой ответ был немного вялым. Кое-что еще приземлилось на моем столе, но я займусь этим в ближайшие день или два. Спасибо еще раз.   -  person Jack    schedule 14.03.2012


Ответы (2)


Вот реализация вашего примера.

Добавьте следующий импорт:

import play.api.libs.ws.WS
import play.api.mvc.BodyParsers.parse
import scala.xml.XML

Добавьте следующий маршрут:

case GET(Path("/testservice")) & QueryString(qs) => Action{ request =>
    Async {
      val backendUrl = QueryString(qs,"target") map (_.get(0)) getOrElse("http://localhost:8080/api/token")
      val tokenData = QueryString(qs,"data") map (_.get(0)) getOrElse("<auth>john</auth>")
      WS.url(backendUrl).post(XML loadString tokenData).map { response =>
      Ok(<html><h1>Posted to {backendUrl}</h1>
         <body>
           <div><p><b>Request body:</b></p>{tokenData}</div>
           <div><p><b>Response body:</b></p>{response.body}</div>
         </body></html>).as("text/html") }
      }
    }

Все, что он делает, это пересылает запрос GET серверной службе как запрос POST. Серверная служба указывается в параметре запроса как target, а тело запроса POST указывается в параметре запроса как data (должен быть допустимым XML). В качестве бонуса запрос обрабатывается асинхронно (отсюда Async). Как только ответ от внутренней службы получен, внешняя служба отвечает некоторым базовым HTML-кодом, показывающим ответ внутренней службы.

Если вы хотите использовать тело запроса, я бы предложил добавить следующий маршрут POST, а не GET (опять же, в этой реализации тело должно быть допустимым XML):

case POST(Path("/testservice")) & QueryString(qs) => Action(parse.tolerantXml){ request =>
    Async {
      val backendUrl = QueryString(qs,"target") map (_.get(0)) getOrElse("http://localhost:8080/api/token")
      WS.url(backendUrl).post(request.body).map { response =>
      Ok(<html><h1>Posted to {backendUrl}</h1>
         <body>
           <div><p><b>Request body:</b></p>{request.body}</div>
           <div><p><b>Response body:</b></p>{response.body}</div>
         </body></html>).as("text/html") }
      }
    }

Итак, как вы можете видеть, для вашего HTTP-шлюза вы можете использовать Async и play.api.libs.ws.WS с Akka под капотом, работающим для обеспечения асинхронной обработки (никаких явных актеров не требуется). Удачи в вашем проекте Play2/Akka2.

person romusz    schedule 12.03.2012

Отличный ответ от romusz

Другой способ сделать (блокирующий) запрос HTTP GET:

import play.api.libs.ws.WS.WSRequestHolder  
import play.api.libs.ws.WS.url  
import play.api.libs.concurrent.Promise  
import play.api.libs.ws.Response

val wsRequestHolder: WSRequestHolder = url("http://yourservice.com")  
val promiseResponse: Promise[Response] = wsRequestHolder.get()  
val response = promiseResponse.await.get

println("HTTP status code: " + response.status)
println("HTTP body: " + response.body)
person Tue    schedule 22.03.2012