如何用 Akka-http 请求 JSON 或 XML?
How to request JSON or XML with Akka-http?
我离开 Akka 世界几个月了,显然我已经失去了我的魔力。我正在尝试基于 Accept header.
编写 returns 一个 XML 或 JSON 文档的 Web 服务
但是,我无法让编组器工作(returns 406,只接受 text/plain)。这是我的:
trait MyMarshallers extends DefaultJsonProtocol with SprayJsonSupport with ScalaXmlSupport {
implicit def ec: ExecutionContext
implicit val itemJsonFormat = jsonFormat3(MyPerson)
def marshalCatalogItem(obj: MyPerson): NodeSeq =
<MyPerson>
<id>
{obj.ID}
</id>
<name>
{obj.Name}
</name>
<age>
{obj.Age}
</age>
</MyPerson>
def marshalCatalogItems(items: Iterable[MyPerson]): NodeSeq =
<Team>
{items.map(marshalCatalogItem)}
</Team>
implicit def catalogXmlFormat = Marshaller.opaque[Iterable[MyPerson], NodeSeq](marshalCatalogItems)
implicit def catalogItemXmlFormat = Marshaller.opaque[MyPerson, NodeSeq](marshalCatalogItem)
implicit val catalogMarshaller: ToResponseMarshaller[Iterable[MyPerson]] = Marshaller.oneOf(
Marshaller.withFixedContentType(MediaTypes.`application/json`) { catalog ⇒
HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`),
catalog.map(i ⇒ MyPerson(i.ID, i.Name, i.Age))
.toJson.compactPrint))
}
,
Marshaller.withOpenCharset(MediaTypes.`application/xml`) { (catalog, charset) ⇒
HttpResponse(entity = HttpEntity.CloseDelimited(ContentType(MediaTypes.`application/xml`, HttpCharsets.`UTF-8`),
Source.fromFuture(Marshal(catalog.map(i => MyPerson(i.ID, i.Name, i.Age)))
.to[NodeSeq])
.map(ns ⇒ ByteString(ns.toString()))
)
)
}
)
}
我的路线是这样的:
class MyService extends MyMarshallers {
implicit val system = ActorSystem("myService")
implicit val materializer = ActorMaterializer()
implicit val ec: ExecutionContext = system.dispatcher
...
def route = ...
(get & path("teams")) {
parameters('name.as[String]) { id =>
complete {
getTeam(id)
}
}
...
}
如果我请求 /,我得到纯文本,但如果我请求 application/xml 或 application/json,我得到 406。
AKKA-HTTP 如何决定它将接受哪些内容类型?我刚刚将所有内容更新到 Akka 2.4.6。
抱歉,我知道了。上面的代码有两个问题,其中一个解决了问题:
- 问题 1 - 更改为使用 fromIterator 而不是
XML 编组器。
- 问题 2 - 我的 getTeam() 方法返回一个 Iterable。我将其更改为 Seq。
现在一切正常。
我离开 Akka 世界几个月了,显然我已经失去了我的魔力。我正在尝试基于 Accept header.
编写 returns 一个 XML 或 JSON 文档的 Web 服务但是,我无法让编组器工作(returns 406,只接受 text/plain)。这是我的:
trait MyMarshallers extends DefaultJsonProtocol with SprayJsonSupport with ScalaXmlSupport {
implicit def ec: ExecutionContext
implicit val itemJsonFormat = jsonFormat3(MyPerson)
def marshalCatalogItem(obj: MyPerson): NodeSeq =
<MyPerson>
<id>
{obj.ID}
</id>
<name>
{obj.Name}
</name>
<age>
{obj.Age}
</age>
</MyPerson>
def marshalCatalogItems(items: Iterable[MyPerson]): NodeSeq =
<Team>
{items.map(marshalCatalogItem)}
</Team>
implicit def catalogXmlFormat = Marshaller.opaque[Iterable[MyPerson], NodeSeq](marshalCatalogItems)
implicit def catalogItemXmlFormat = Marshaller.opaque[MyPerson, NodeSeq](marshalCatalogItem)
implicit val catalogMarshaller: ToResponseMarshaller[Iterable[MyPerson]] = Marshaller.oneOf(
Marshaller.withFixedContentType(MediaTypes.`application/json`) { catalog ⇒
HttpResponse(entity = HttpEntity(ContentType(MediaTypes.`application/json`),
catalog.map(i ⇒ MyPerson(i.ID, i.Name, i.Age))
.toJson.compactPrint))
}
,
Marshaller.withOpenCharset(MediaTypes.`application/xml`) { (catalog, charset) ⇒
HttpResponse(entity = HttpEntity.CloseDelimited(ContentType(MediaTypes.`application/xml`, HttpCharsets.`UTF-8`),
Source.fromFuture(Marshal(catalog.map(i => MyPerson(i.ID, i.Name, i.Age)))
.to[NodeSeq])
.map(ns ⇒ ByteString(ns.toString()))
)
)
}
)
}
我的路线是这样的:
class MyService extends MyMarshallers {
implicit val system = ActorSystem("myService")
implicit val materializer = ActorMaterializer()
implicit val ec: ExecutionContext = system.dispatcher
...
def route = ...
(get & path("teams")) {
parameters('name.as[String]) { id =>
complete {
getTeam(id)
}
}
...
}
如果我请求 /,我得到纯文本,但如果我请求 application/xml 或 application/json,我得到 406。
AKKA-HTTP 如何决定它将接受哪些内容类型?我刚刚将所有内容更新到 Akka 2.4.6。
抱歉,我知道了。上面的代码有两个问题,其中一个解决了问题:
- 问题 1 - 更改为使用 fromIterator 而不是 XML 编组器。
- 问题 2 - 我的 getTeam() 方法返回一个 Iterable。我将其更改为 Seq。
现在一切正常。