Akka:如何将消息内容包装到 HTTP 响应中?
Akka: How to wrap a message content into an HTTP response?
在我的 Akka-http 路由中,我收到一条特定的消息,我想将其内容包装为错误消息,例如:
val response:Future[T] = (actor ? command).mapTo[T]
response match {
case err : Future[InvalidRequest] =>
HttpResponse(408, entity = err.map(_.toJson).????)
case r : Future[T] => r.map(_.toJson)
}
case class InvalidRequest(error:String)
implicit val invalidRequestFormat = jsonFormat1(InvalidRequest)
但这不起作用。如何将其映射为 json 格式的文本?
我想我可以为您正在尝试做的事情提供一个通用的解决方案。您可以首先创建一个 returns a Route
的方法,如下所示:
def service[T:ClassTag](actor:ActorRef, command:Any)
(implicit timeout:Timeout, _marshaller: ToResponseMarshaller[T]):Route = {
val fut = (actor ? command).mapTo[ServiceResponse]
onComplete(fut){
case util.Success(ir:InvalidRequest) =>
complete(StatusCodes.BadRequest, ir)
case util.Success(t:T) =>
complete(t)
case util.Failure(ex) =>
complete(StatusCodes.InternalServerError )
}
}
此方法通过 ask 向提供的 actor 发出请求,并获取表示结果的 Future
。然后它使用 onComplete
指令对 InvalidResponse
情况应用特殊处理。重要的是你在范围内有一个隐式的 ToResponseMarshaller[T]
,因为成功案例需要它。
然后,假设您定义了以下 类 和格式化程序:
trait ServiceResponse
case class Foo(id:Int) extends ServiceResponse
implicit val fooFormat = jsonFormat1(Foo)
case class InvalidRequest(error:String) extends ServiceResponse
implicit val invalidRequestFormat = jsonFormat1(InvalidRequest)
您可以在路由树中使用新的 service
方法,如下所示:
val routes:Route = {
path("api" / "foo"){
get{
service[Foo](fooActor, FooActor.DoFoo)
}
}
}
您的示例的问题在于您在构建响应之前没有等待 Future
完成。您试图匹配 Future
的基础类型,它在运行时被擦除消除,因此以这种方式尝试和匹配不是一个好主意。相反,您需要等到它完成,然后查看 Future
后面的类型。
在我的 Akka-http 路由中,我收到一条特定的消息,我想将其内容包装为错误消息,例如:
val response:Future[T] = (actor ? command).mapTo[T]
response match {
case err : Future[InvalidRequest] =>
HttpResponse(408, entity = err.map(_.toJson).????)
case r : Future[T] => r.map(_.toJson)
}
case class InvalidRequest(error:String)
implicit val invalidRequestFormat = jsonFormat1(InvalidRequest)
但这不起作用。如何将其映射为 json 格式的文本?
我想我可以为您正在尝试做的事情提供一个通用的解决方案。您可以首先创建一个 returns a Route
的方法,如下所示:
def service[T:ClassTag](actor:ActorRef, command:Any)
(implicit timeout:Timeout, _marshaller: ToResponseMarshaller[T]):Route = {
val fut = (actor ? command).mapTo[ServiceResponse]
onComplete(fut){
case util.Success(ir:InvalidRequest) =>
complete(StatusCodes.BadRequest, ir)
case util.Success(t:T) =>
complete(t)
case util.Failure(ex) =>
complete(StatusCodes.InternalServerError )
}
}
此方法通过 ask 向提供的 actor 发出请求,并获取表示结果的 Future
。然后它使用 onComplete
指令对 InvalidResponse
情况应用特殊处理。重要的是你在范围内有一个隐式的 ToResponseMarshaller[T]
,因为成功案例需要它。
然后,假设您定义了以下 类 和格式化程序:
trait ServiceResponse
case class Foo(id:Int) extends ServiceResponse
implicit val fooFormat = jsonFormat1(Foo)
case class InvalidRequest(error:String) extends ServiceResponse
implicit val invalidRequestFormat = jsonFormat1(InvalidRequest)
您可以在路由树中使用新的 service
方法,如下所示:
val routes:Route = {
path("api" / "foo"){
get{
service[Foo](fooActor, FooActor.DoFoo)
}
}
}
您的示例的问题在于您在构建响应之前没有等待 Future
完成。您试图匹配 Future
的基础类型,它在运行时被擦除消除,因此以这种方式尝试和匹配不是一个好主意。相反,您需要等到它完成,然后查看 Future
后面的类型。