嗨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来说相当新,但对我来说看起来很奇怪,将(否则是隐式的)对象带入范围会产生如此奇怪的副作用。你们中有谁知道发生了什么事吗?
答案 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之一来简化处理请求标题的过程。