BodyParser.Raw 怎么玩!框架工作?
how does BodyParser.Raw in Play! framework work?
我对 Play 中的 BodyParser.Raw
有疑问!框架。 The official document 说:
Parses the body as a RawBuffer
. This will attempt to store the body
in memory, up to Play’s configured memory buffer size, but fallback to
writing it out to a File if that’s exceeded.
我很难理解上面的描述。这是否意味着以下 -
如果我将以下配置放入我的 application.conf
文件中:
play.http.parser.maxMemoryBuffer=128k
play.http.parser.maxDiskBuffer=1G
并说我的请求 body 大小为 15MB,然后播放!将 read/parse 来自请求 body 的前 128k,将其写入文件,然后 stream/parse 来自请求 body 的下一个 128k,将其写入同一个文件, ...,直到 15MB 的请求 body 被完全解析?这意味着我们只使用了 128k 内存,并且我们能够处理大小为 15MB 的请求 body??
我知道这听起来好得令人难以置信...
有人可以解释一下吗?
更新:
如果有人在这里遇到同样的问题,我想在这里添加一些更新。所以@Ivan Kurchenko 是对的(见下面他的回答):BodyParser.Raw
可用于 POST
比配置的 play.http.parser.maxMemoryBuffer
大的请求 body。玩!在这种情况下,将使用磁盘缓冲请求。换句话说,您可以 POST
一个比 JVM 中的可用内存更大的大请求 body。
我使用 Chrome(以及 Firefox)测试失败的原因是我默认启用了 CSRF 过滤器。一旦我禁用它,一切正常。比如下面的配置,
play.http.parser.maxMemoryBuffer=1k
play.http.parser.maxDiskBuffer=4G
play.filters.disabled+=play.filters.csrf.CSRFFilter
表示如果请求 body 大于 1k,播放!将使用您的磁盘来缓冲您的请求(当然,我禁用了 CSRF 过滤器)。现在,通过这个配置,我可以成功上传超过3G的电影。所以确实,如果你需要处理一个大的请求,可以使用 BodyParser.Raw
。 HTH!
不是真的 - 如果请求大小超过内存阈值,在您配置为 play.http.parser.maxMemoryBuffer=128k
的情况下,整个请求正文将写入临时文件或写入内存。然后下一个解析体也将从文件或内存中流式传输。
一起来看看:
BodyParser.raw - creates RawBuffer
inside, like for instance here https://github.com/playframework/playframework/blob/6d0789468909d5d7bdabc6c4207337bd7a7ca9b1/core/play/src/main/scala/play/api/mvc/BodyParsers.scala#L612
在 RawBuffer
里面有两个我们感兴趣的方法:
push method implementation - 接受传入字节且总大小超过缓冲区大小执行 backToTemporaryFile
- 表示将所有请求写入临时文件。
@volatile private var inMemory: ByteString = initialData
@volatile private var backedByTemporaryFile: TemporaryFile = _
@volatile private var outStream: OutputStream = _
private[play] def push(chunk: ByteString): Unit = {
if (inMemory != null) { //checks whether current in memory buffer exists
//if next readed chunk of request body exceeds in memory buffer size
if (chunk.length + inMemory.size > memoryThreshold) {
backToTemporaryFile() // create temporary file
outStream.write(chunk.toArray)// write buffer to temporary file
} else {
inMemory = inMemory ++ chunk // append in memory buffer with next chunk
}
} else {
outStream.write(chunk.toArray) // append in memory buffer with next chunk
}
}
然后 asBytes method implementation - which on its own side read bytes if in memory buffer exists. Or asFile implementation 从临时文件中读取字节。
另请注意:如果传入请求正文大小超过 play.http.parser.maxDiskBuffer
中的配置值,Play 将响应 413 - REQUEST_ENTITY_TOO_LARGE 状态。
我对 Play 中的 BodyParser.Raw
有疑问!框架。 The official document 说:
Parses the body as a
RawBuffer
. This will attempt to store the body in memory, up to Play’s configured memory buffer size, but fallback to writing it out to a File if that’s exceeded.
我很难理解上面的描述。这是否意味着以下 -
如果我将以下配置放入我的 application.conf
文件中:
play.http.parser.maxMemoryBuffer=128k
play.http.parser.maxDiskBuffer=1G
并说我的请求 body 大小为 15MB,然后播放!将 read/parse 来自请求 body 的前 128k,将其写入文件,然后 stream/parse 来自请求 body 的下一个 128k,将其写入同一个文件, ...,直到 15MB 的请求 body 被完全解析?这意味着我们只使用了 128k 内存,并且我们能够处理大小为 15MB 的请求 body??
我知道这听起来好得令人难以置信...
有人可以解释一下吗?
更新:
如果有人在这里遇到同样的问题,我想在这里添加一些更新。所以@Ivan Kurchenko 是对的(见下面他的回答):BodyParser.Raw
可用于 POST
比配置的 play.http.parser.maxMemoryBuffer
大的请求 body。玩!在这种情况下,将使用磁盘缓冲请求。换句话说,您可以 POST
一个比 JVM 中的可用内存更大的大请求 body。
我使用 Chrome(以及 Firefox)测试失败的原因是我默认启用了 CSRF 过滤器。一旦我禁用它,一切正常。比如下面的配置,
play.http.parser.maxMemoryBuffer=1k
play.http.parser.maxDiskBuffer=4G
play.filters.disabled+=play.filters.csrf.CSRFFilter
表示如果请求 body 大于 1k,播放!将使用您的磁盘来缓冲您的请求(当然,我禁用了 CSRF 过滤器)。现在,通过这个配置,我可以成功上传超过3G的电影。所以确实,如果你需要处理一个大的请求,可以使用 BodyParser.Raw
。 HTH!
不是真的 - 如果请求大小超过内存阈值,在您配置为 play.http.parser.maxMemoryBuffer=128k
的情况下,整个请求正文将写入临时文件或写入内存。然后下一个解析体也将从文件或内存中流式传输。
一起来看看:
BodyParser.raw - creates RawBuffer
inside, like for instance here https://github.com/playframework/playframework/blob/6d0789468909d5d7bdabc6c4207337bd7a7ca9b1/core/play/src/main/scala/play/api/mvc/BodyParsers.scala#L612
在 RawBuffer
里面有两个我们感兴趣的方法:
push method implementation - 接受传入字节且总大小超过缓冲区大小执行 backToTemporaryFile
- 表示将所有请求写入临时文件。
@volatile private var inMemory: ByteString = initialData
@volatile private var backedByTemporaryFile: TemporaryFile = _
@volatile private var outStream: OutputStream = _
private[play] def push(chunk: ByteString): Unit = {
if (inMemory != null) { //checks whether current in memory buffer exists
//if next readed chunk of request body exceeds in memory buffer size
if (chunk.length + inMemory.size > memoryThreshold) {
backToTemporaryFile() // create temporary file
outStream.write(chunk.toArray)// write buffer to temporary file
} else {
inMemory = inMemory ++ chunk // append in memory buffer with next chunk
}
} else {
outStream.write(chunk.toArray) // append in memory buffer with next chunk
}
}
然后 asBytes method implementation - which on its own side read bytes if in memory buffer exists. Or asFile implementation 从临时文件中读取字节。
另请注意:如果传入请求正文大小超过 play.http.parser.maxDiskBuffer
中的配置值,Play 将响应 413 - REQUEST_ENTITY_TOO_LARGE 状态。