Java Akka Http请求和响应模式
我有一个要求,客户机调用通过akka http创建的post REST端点。一旦请求在post方法中,我就需要将post对象传递给流(由源、多个流和接收器等组成),并从接收器获取响应,以便将响应返回给客户端 我已经阅读了一些文章,看到了下面的代码,但我担心我不想为每个请求实现流。我只想具体化一个流,并继续将元素传递给该流 以下是我所看到的高层次内容:Java Akka Http请求和响应模式,java,scala,akka,akka-stream,akka-http,Java,Scala,Akka,Akka Stream,Akka Http,我有一个要求,客户机调用通过akka http创建的post REST端点。一旦请求在post方法中,我就需要将post对象传递给流(由源、多个流和接收器等组成),并从接收器获取响应,以便将响应返回给客户端 我已经阅读了一些文章,看到了下面的代码,但我担心我不想为每个请求实现流。我只想具体化一个流,并继续将元素传递给该流 以下是我所看到的高层次内容: val route: Route = path("dummy path") { p => get { (extrac
val route: Route =
path("dummy path") { p =>
get {
(extract(_.request) & extractMaterializer) { (req, mat) ⇒
**Source.single(req).runWith(sink)(mat)**
complete {
s"<h1>Say hello to akka-http. p=$p</h1>"
}
}
}
}
或者,我还可以在我的用例中加入其他内容。我想你想要的是让请求的处理通过流[只具体化一次],并从流中将响应发送回用户。可能是队列源,中间的参与者可以执行此任务
import java.util.concurrent.TimeUnit
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives.{
get,
onSuccess,
pathEnd,
pathPrefix
}
import akka.pattern.ask
import akka.stream.scaladsl.{Keep, Sink, Source, SourceQueueWithComplete}
import akka.stream.{ActorMaterializer, OverflowStrategy, QueueOfferResult}
import akka.util.Timeout
import akka.http.scaladsl.server.directives.RouteDirectives.complete
import com.typesafe.config.ConfigFactory
import scala.concurrent.ExecutionContext
object TestApp2 extends App {
implicit val actorSystem = ActorSystem("test-system")
implicit val mat = ActorMaterializer()
implicit val ec = mat.executionContext
val streamSource = Source
.queue[(Message, ActorRef)](100, OverflowStrategy.dropNew)
.map { p =>
//do anything here
println("I am processing request")
("It works", p._2)
}
.toMat(Sink.foreach { resp =>
resp._2 ! resp._1
})(Keep.left)
.run()
implicit val timeout = Timeout(
10000,
TimeUnit.MILLISECONDS
)
val internalActor =
actorSystem.actorOf(Props(new InternalActor(streamSource)))
Http(actorSystem)
.bindAndHandle(
getRoutes(internalActor),
"0.0.0.0",
8080
)
def getRoutes(
internalActor: ActorRef
)(implicit mat: ActorMaterializer, ec: ExecutionContext, timeout: Timeout) = {
pathPrefix("healthcheck") {
get {
pathEnd {
val responseReturned = internalActor ? Message()
onSuccess(responseReturned) {
case response: String =>
complete(response)
case _ => complete("error")
}
}
}
}
}
}
case class Message()
class InternalActor(streamSource: SourceQueueWithComplete[(Message, ActorRef)])(
implicit ec: ExecutionContext
) extends Actor {
override def receive: Receive = {
case m: Message =>
val senderRef = sender()
streamSource.offer((m, senderRef)).map {
case QueueOfferResult.Enqueued => // do nothing for success
case QueueOfferResult.Dropped => senderRef ! "error" // return error in case of backpressure
case QueueOfferResult.Failure(ex) => senderRef ! "error" // return error
case QueueOfferResult.QueueClosed => senderRef ! "error" // return error
}
}
}
卷曲“
它可以工作处理的输出是什么?是否要在数据仍然传入时开始流式输出结果?Hi jrudolph,Request是post http请求,响应将是一个对象(普通pojo),封送到json响应,并通过相同的http调用返回给用户。我现在在我的场景中使用akka http低级DSL(我只想具体化我的流一次),它按照预期工作。不过,有时当客户端应用程序发出多个http调用时,有时我的流被挂起并超时,并且没有返回响应。这是因为在超时期间,HttpEntity.Default与Strict相比返回。我尝试使用.toStict(),但问题仍然存在?我做错了吗?嗨,jrudolph,关于你的问题:你想在数据仍然传入时开始流式输出结果吗->我相信没有。原因是一旦我收到http请求,我只想在流中进一步处理这个问题。处理完成后,将响应流式输出回来。
import java.util.concurrent.TimeUnit
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives.{
get,
onSuccess,
pathEnd,
pathPrefix
}
import akka.pattern.ask
import akka.stream.scaladsl.{Keep, Sink, Source, SourceQueueWithComplete}
import akka.stream.{ActorMaterializer, OverflowStrategy, QueueOfferResult}
import akka.util.Timeout
import akka.http.scaladsl.server.directives.RouteDirectives.complete
import com.typesafe.config.ConfigFactory
import scala.concurrent.ExecutionContext
object TestApp2 extends App {
implicit val actorSystem = ActorSystem("test-system")
implicit val mat = ActorMaterializer()
implicit val ec = mat.executionContext
val streamSource = Source
.queue[(Message, ActorRef)](100, OverflowStrategy.dropNew)
.map { p =>
//do anything here
println("I am processing request")
("It works", p._2)
}
.toMat(Sink.foreach { resp =>
resp._2 ! resp._1
})(Keep.left)
.run()
implicit val timeout = Timeout(
10000,
TimeUnit.MILLISECONDS
)
val internalActor =
actorSystem.actorOf(Props(new InternalActor(streamSource)))
Http(actorSystem)
.bindAndHandle(
getRoutes(internalActor),
"0.0.0.0",
8080
)
def getRoutes(
internalActor: ActorRef
)(implicit mat: ActorMaterializer, ec: ExecutionContext, timeout: Timeout) = {
pathPrefix("healthcheck") {
get {
pathEnd {
val responseReturned = internalActor ? Message()
onSuccess(responseReturned) {
case response: String =>
complete(response)
case _ => complete("error")
}
}
}
}
}
}
case class Message()
class InternalActor(streamSource: SourceQueueWithComplete[(Message, ActorRef)])(
implicit ec: ExecutionContext
) extends Actor {
override def receive: Receive = {
case m: Message =>
val senderRef = sender()
streamSource.offer((m, senderRef)).map {
case QueueOfferResult.Enqueued => // do nothing for success
case QueueOfferResult.Dropped => senderRef ! "error" // return error in case of backpressure
case QueueOfferResult.Failure(ex) => senderRef ! "error" // return error
case QueueOfferResult.QueueClosed => senderRef ! "error" // return error
}
}
}