如何在后台实现Akka HTTP封送处理? [英] How is Akka HTTP marshaling implemented under the hood?

查看:167
本文介绍了如何在后台实现Akka HTTP封送处理?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将编译以下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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆