喷涂:在范围内引入RequestContext会导致超时

时间:2013-12-27 08:58:40

标签: scala http-headers spray

嗨scala和喷人!

RequestContext中提取HTTP“Accept”标头并在其上进行匹配时,我遇到了一个小问题。像这样的正常路线:

get {
  respondWithMediaType(`text/plain`) {
    complete ( "Hello World!" )
  }
}

它就像一个魅力。但每当我将上下文纳入范围时(如the documentation for directives中所述):

get { context => {
  respondWithMediaType(`text/plain`) {
    complete ( "Hello World!" )
  }
} }

结果将成为以下错误消息:

The server was not able to produce a timely response to your request.

我对Spray来说相当新,但对我来说看起来很奇怪,将(否则是隐式的)对象带入范围会产生如此奇怪的副作用。你们中有谁知道发生了什么事吗?

1 个答案:

答案 0 :(得分:8)

很少需要直接访问RequestContext。实际上,如果要编写自定义指令,则只需要它。通常可以使用预定义指令之一来处理常见任务和提取通常的数据位。

您希望做的是手动内容类型协商。实际上,您不必手动执行此操作,因为喷涂会针对常见数据结构自动执行内容类型。您的示例可以缩短为

get {
  complete("Hello World!")
}

使用字符串调用complete时,响应将始终为text/plain类型。如果客户端发送的请求的Accept标头不接受text/plain,则服务器已拒绝该请求。

如果要自定义可从Scala数据类型提供的各种内容类型,则需要提供自定义Marshaller。请参阅the documentation了解如何实现这一目标。

回答原始问题为什么添加context =>会导致请求超时:这是因为预定义指令已经是RequestContext => Unit类型。所以,写作

respondWithMediaType(`text/plain`) {
  complete("Hello World!")
}

完全等同于(即自动扩展到)

ctx => respondWithMediaType(`text/plain`) {
  complete("Hello World!")
}.apply(ctx)

因此,如果您只手动添加ctx =>,但不添加apply调用,则传入请求永远不会进入内部路由,因此永远不会完成。编译器不会捕获此类错误,因为路由的类型为RequestContext => Unit,因此带有和没有apply调用的变量的变量都是有效的。我们将来are going to improve this

有关如何构建路线的详细信息,请参阅the documentation

最后,如果您需要提取标题或其值,您可以使用predefined HeaderDirectives之一来简化处理请求标题的过程。