如何在后台实现Akka HTTP封送处理? [英] How is Akka HTTP marshaling implemented under the hood?
问题描述
将编译以下Scala代码:
The following Scala code compiles:
import spray.json.DefaultJsonProtocol._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.server.Directives.complete
case class Item(name: String, id: Long)
implicit val itemFormat = jsonFormat2(Item)
val item = Item("xbox", 123)
complete(item)
在工作表中具有以下输出:
with the following output in the worksheet:
import spray.json.DefaultJsonProtocol._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.server.Directives.complete
defined class Item
itemFormat: spray.json.RootJsonFormat[Item] = spray.json.ProductFormatsInstances$$anon$2@4528e00
item: Item = Item(xbox,123)
res0: akka.http.scaladsl.server.StandardRoute = <function1>
但是当我注释掉导入akka.http.scaladsl.marshallers时。 sprayjson.SprayJsonSupport ._
我收到以下编译错误:
But when I comment out the import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
I get the following compilation error:
Error:(11, 11) type mismatch;
found : A$A562.this.Item
required: akka.http.scaladsl.marshalling.ToResponseMarshallable
complete(item);}
^
导入对您有何影响?
推荐答案
当您执行 RequestContext#complete(response)
时,它将以 ToResponseMarshallable
作为输入。
When you do RequestContext#complete(response)
, which takes ToResponseMarshallable
as input.
package akka.http.scaladsl.server
@InternalApi
private[http] class RequestContextImpl(
override def complete(trm: ToResponseMarshallable): Future[RouteResult] =
trm(request)(executionContext)
.fast.map(res ⇒ RouteResult.Complete(res))(executionContext)
.fast.recover {
case Marshal.UnacceptableResponseContentTypeException(supported) ⇒
RouteResult.Rejected(UnacceptedResponseContentTypeRejection(supported) :: Nil)
case RejectionError(rej) ⇒
RouteResult.Rejected(rej :: Nil)
}(executionContext)
}
SprayJsonSupport
是定义隐式 Marshallers
的对象,它们是给出 Marshallable
的对象p>
SprayJsonSupport
is the object where implicit Marshallers
are defined and they are the ones which gives Marshallable
package akka.http.scaladsl.marshallers.sprayjson
trait SprayJsonSupport {
implicit def sprayJsonMarshallerConverter[T](writer: RootJsonWriter[T])(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[T] =
sprayJsonMarshaller[T](writer, printer)
implicit def sprayJsonMarshaller[T](implicit writer: RootJsonWriter[T], printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[T] =
sprayJsValueMarshaller compose writer.write
implicit def sprayJsValueMarshaller(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[JsValue] =
Marshaller.StringMarshaller.wrap(MediaTypes.`application/json`)(printer)
}
如果不要导入 SprayJsonSupport
,您将不会得到隐式的 Marshallers
,它将您的案例类编组为所需的输出,即 JSObject
。
If you don't import SprayJsonSupport
, you won't get implicit Marshallers
which marshall your case class to desired output which is JSObject
.
如果您不想导入 SprayJsonSupport
为JsonMarshallers提供默认设置,编写您自己的文件或从 JsonSpraySupport
复制粘贴这些编组。
If you don't want to import SprayJsonSupport
that provides default toJsonMarshallers, write your own, or copy paste the marshallers from JsonSpraySupport
.
示例
object GetHttpRoutes {
case class Acknowledge(status: String)
implicit val itemFormat = jsonFormat1(Acknowledge)
implicit def toJsonMarshallerConverter[Entity](writer: RootJsonWriter[Entity])(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[Entity] =
toJsonMarshaller[Entity](writer, printer)
implicit def toJsonMarshaller[Entity](implicit writer: RootJsonWriter[Entity], printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[Entity] =
toJsValueMarshaller compose writer.write
implicit def toJsValueMarshaller(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[JsValue] =
Marshaller.StringMarshaller.wrap(MediaTypes.`application/json`)(printer)
val get_api =
path("") {
get { context =>
context.complete {
Acknowledge(status = "xbox")
}
}
}
}
trait HTTPRoutes {
implicit val system: ActorSystem
implicit val materializer: ActorMaterializer
val route = GetHttpRoutes.get_api
}
测试
class GetHttpRoutesCompSpecs extends WordSpec with Matchers with ScalatestRouteTest with BeforeAndAfterAll {
"HTTP GET endpoints" should {
"returns xbox on /" in {
Get("/") ~> GetHttpRoutes.get_api ~> check {
responseAs[String] shouldEqual """{"status":"xbox"}"""
}
}
}
}
这篇关于如何在后台实现Akka HTTP封送处理?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!