喷射路由:如何使用不同的内容类型进行响应?

8
在spray中,我希望能够根据给定的“Accept”头部信息响应不同类型的内容。在rompetroll的问题中看到了一些建议,但我想知道是否有已经实现的标准方法(即简单或已实现的方法)。
本质上,我想要实现的是类似以下的功能:
path("somepath") {
  get {
    // Find whatever we would like to return (lazily)
    ...
    // Marshall resource and complete depending on the `Accept` header
    ...
  }
}

提前感谢你的帮助。

2个回答

15

请查看此次提交中的测试。

以下是我复制的参考内容:

case class Data(name: String, age: Int)
object Data {
  import spray.json.DefaultJsonProtocol._
  import spray.httpx.SprayJsonSupport._

  // don't make those `implicit` or you will "ambiguous implicit" errors when compiling
  val jsonMarshaller: Marshaller[Data] = jsonFormat2(Data.apply)
  val xmlMarshaller: Marshaller[Data] =
    Marshaller.delegate[Data, xml.NodeSeq](MediaTypes.`text/xml`) { (data: Data) ⇒
      <data><name>{ data.name }</name><age>{ data.age }</age></data>
    }

  implicit val dataMarshaller: ToResponseMarshaller[Data] =
    ToResponseMarshaller.oneOf(MediaTypes.`application/json`, MediaTypes.`text/xml`)  (jsonMarshaller, xmlMarshaller)
}

你可以在路由中使用complete,这将自动处理内容类型协商:

get {
  complete(Data("Ida", 83))
}

有点儿愚蠢的问题,但在上面的调用 jsonFormat2(Data.apply) 中,.apply 是在哪里定义的? - ivcheto
这是由Scala编译器自动生成的,用于支持Data(...)语法而不需要编写new Data(...)case class - jrudolph

8
Spray会检查请求头的 Accept 值并进行验证。如果路由返回的是 application/json 或者 text/plain,而客户端接受的是 image/jpeg,那么Spray就会返回 406 Not Acceptable。如果客户端从该路由请求 application/json 或者 text/plain,那么他将会收到匹配的 Content-Type 的响应。
这里的主要技巧是使用正确的序列化程序来返回对象。 您可以在此处阅读有关序列化的更多信息:这里
此外,您还可以使用 respondWithMediaType 指令覆盖 MediaType,但我认为最好使用正确的序列化程序。

这有很多意义。我完全从文档中错过了这一点。谢谢 :) - Jens Egholm
1
同意,respondWithMediaType 通常不是正确的方法。Marshallers 已经包含了所有逻辑来执行自动内容类型协商。请参阅我的答案,了解如何将不同内容类型的 marshallers 组合成一个接受所有内容类型并为它们选择正确 marshaller 的方法。 - jrudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接