10

在 Rails 中,我能够执行类似于以下的操作:

respond_to do |format|
  format.xml { ... }
  format.json { ... }
end

并且将根据客户端在 Accept 标头中提供的内容执行相应的块。

如何在 Play 2.0 (Scala) 中做同样的事情?

我想做一些看起来大致像这样的事情:

try {
  Resources.delete(id)
  Ok("done")
} 
catch { 
  case e: ClientReportableException =>
    ?? match { 
      case "application/xml" => Ok(<error>{e.message}</error>)
      case "application/json" => Ok(...)
  }
}

是否有一个 Play 习惯用法,或者我只是从请求中获取 Accept 标头的值?

4

2 回答 2

14

在 Play 2.1 中,您可以编写以下代码:

request match {
  case Accepts.Xml() => Ok(<error>{e.message}</error>)
  case Accepts.Json() => Ok(…)
}

case 语句按照它们编写的顺序进行尝试,因此如果您的客户端将 HTTPAccept标头设置*/*为第一个,则将匹配(在此示例中case Accepts.Xml())。因此,您通常希望先编写Accepts.Html()案例,因为浏览器将Accept标题设置为*/*.

(注意:对于 Java 中的类似问题,您可能也对此答案感兴趣)

于 2012-06-16T09:32:32.813 回答
1

我刚刚发布了一个Play!用于内容协商的 2.0 模块称为 mimerender ( http://github.com/martinblech/play-mimerender )。

这个想法是您必须定义从域类到不同表示的映射:

val m = mapping(
  "text/html" -> { s: String => views.html.index(s) },
  "application/xml" -> { s: String => <message>{s}</message> },
  "application/json" -> { s: String => toJson(Map("message" -> toJson(s))) },
  "text/plain" -> identity[String]_
)

完成一次后,您可以在所有控制器中重用该映射:

object Application extends Controller {
  def index = Action { implicit request =>
    m.status(200)("Hello, world!")
  }
}

请注意,这是一个非常早的版本,仅在 Play 2.0.4 上进行了测试

于 2012-12-12T22:06:05.463 回答