我是Scala的新手。 如在https://www.playframework.com/documentation/2.3.x/ScalaHttpFilters中的播放框架官方文档中所述:
Play提供了一个名为EssentialFilter的低级过滤器API 让您完全访问请求的正文。
但是没有任何方法可以访问requestHeader
对象中的请求正文。
import play.api.Logger
import play.api.mvc._
import play.api.libs.concurrent.Execution.Implicits.defaultContext
object LoggingFilter extends EssentialFilter {
def apply(nextFilter: EssentialAction) = new EssentialAction {
def apply(requestHeader: RequestHeader) = {
val startTime = System.currentTimeMillis
nextFilter(requestHeader).map { result =>
val endTime = System.currentTimeMillis
val requestTime = endTime - startTime
Logger.info(s"${requestHeader.method} ${requestHeader.uri}" +
s" took ${requestTime}ms and returned ${result.header.status}")
result.withHeaders("Request-Time" -> requestTime.toString)
}
}
}
}
答案 0 :(得分:5)
您在创建EssentialFilter.apply
时实施的抽象方法EssentialFilter
会返回EssentialAction
,其基本上是从RequestHeader
到Iteratee[Array[Byte], Result]
的函数哪个播放将提供http正文的传入字节块。
如果您不熟悉iteratee API,则上面的签名基本上意味着,接受Array[Byte]
类型的数据块并且迟早会产生Result
那些。
正常游戏Action
是EssentialAction
的子类,使用BodyParser
解析身体,然后提供其结果(Request
将请求标头和已解析的主体都放入一个函数中,该函数又返回Future[Result]
因此,如果您只有一个过滤器,那么过滤器中的next: EssentialAction
基本上就是实际的控制器操作。你可以使用它的Iteratee[Array[Bytes], Result]
并用它包装,这样就可以在身体解析器触摸它之前访问请求的主体。
因此,要实现您想要的目标,您需要了解Iteratees
如何工作以及如何使用Enumeratees
转换或查看输入到迭代中的数据。
播放框架文档有一些关于迭代的非常好的信息:https://www.playframework.com/documentation/2.3.x/Iteratees
James Roper(播放技术主管)也有一篇很好的博客文章可能会有所帮助: https://jazzy.id.au/2012/11/06/iteratees_for_imperative_programmers.html
过滤器如何在游戏中工作,因此无法使用过滤器查看已解析的主体。除非你创建一个将解析主体的枚举,但仍然将字节传递给实际的动作(这将使你解析主体两次)。
如果这是您想要的,那么您最好使用ActionBuilder
并创建自己的自定义Action
,以便查看已解析的请求。
答案 1 :(得分:0)
你不想在过滤级别解析请求体,因为在过滤过程中没有解析主体,你必须缓冲,解析和流,所以最好使用动作组合
object LoggingAction extends ActionBuilder[Request] {
def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
Logger.debug(request.body.asInstanceOf[AnyContentAsJson].json.toString())
block(request)
}
}
在控制器端使用,如
def index = LoggingAction {...