scala - Akka HTTP 编码(marshal)处理在幕后是如何实现的?

标签 scala akka-http

编译以下 Scala 代码:

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)

工作表中的输出如下:

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>

但是当我注释掉 import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._ 时,出现以下编译错误:

Error:(11, 11) type mismatch;
 found   : A$A562.this.Item
 required: akka.http.scaladsl.marshalling.ToResponseMarshallable
complete(item);}
         ^

该导入有何影响?

最佳答案

当您执行 RequestContext#complete(response) 时,它采用 ToResponseMarshallable 作为输入。

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

的对象
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 .

如果您不想导入为 JsonMarshallers 提供默认值的 SprayJsonSupport,请自行编写或从 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"}"""
      }
    }
  }
}

关于scala - Akka HTTP 编码(marshal)处理在幕后是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45068547/

相关文章:

sbt : is there a way to run a single test without tags? 中的 ScalaTest

scala - Akka Streams 的 ActorPublisher 作为 Web 响应的源 - 背压如何工作

scala - akka-http 分块响应连接

scala - 如何从证书链、证书和私钥正确配置 HTTPS?阿卡 HTTP

Scala:通过生成器(可迭代)公开 JDBC ResultSet

Scala 和 mockito 测试 twilio MessageFactory.create() 方法

scala - 获取密封特征的子类

java - `URLEncoder.encode` 的正确编码

scala - 如何将akka http与akka流绑定(bind)?

scala - Akka-http 在一个流中处理来自不同连接的 HttpRequests