Scala 为什么在BodyParser';在Play Framework 2.0中迭代请求挂起?
我试图理解Play2.0框架的反应式I/O概念。为了从一开始就更好地理解,我决定跳过框架的助手来构造不同类型的迭代器,从头开始编写一个自定义的Scala 为什么在BodyParser';在Play Framework 2.0中迭代请求挂起?,scala,playframework,playframework-2.0,iterate,Scala,Playframework,Playframework 2.0,Iterate,我试图理解Play2.0框架的反应式I/O概念。为了从一开始就更好地理解,我决定跳过框架的助手来构造不同类型的迭代器,从头开始编写一个自定义的Iteratee,供BodyParser解析请求体 从和文档中提供的信息以及关于play Responsive I/O的两个演示开始,这就是我想到的: import play.api.mvc._ import play.api.mvc.Results._ import play.api.libs.iteratee.{Iteratee, Input} imp
Iteratee
,供BodyParser
解析请求体
从和文档中提供的信息以及关于play Responsive I/O的两个演示开始,这就是我想到的:
import play.api.mvc._
import play.api.mvc.Results._
import play.api.libs.iteratee.{Iteratee, Input}
import play.api.libs.concurrent.Promise
import play.api.libs.iteratee.Input.{El, EOF, Empty}
01 object Upload extends Controller {
02 def send = Action(BodyParser(rh => new SomeIteratee)) { request =>
03 Ok("Done")
04 }
05 }
06
07 case class SomeIteratee(state: Symbol = 'Cont, input: Input[Array[Byte]] = Empty, received: Int = 0) extends Iteratee[Array[Byte], Either[Result, Int]] {
08 println(state + " " + input + " " + received)
09
10 def fold[B](
11 done: (Either[Result, Int], Input[Array[Byte]]) => Promise[B],
12 cont: (Input[Array[Byte]] => Iteratee[Array[Byte], Either[Result, Int]]) => Promise[B],
13 error: (String, Input[Array[Byte]]) => Promise[B]
14 ): Promise[B] = state match {
15 case 'Done => { println("Done"); done(Right(received), Input.Empty) }
16 case 'Cont => cont(in => in match {
17 case in: El[Array[Byte]] => copy(input = in, received = received + in.e.length)
18 case Empty => copy(input = in)
19 case EOF => copy(state = 'Done, input = in)
20 case _ => copy(state = 'Error, input = in)
21 })
22 case _ => { println("Error"); error("Some error.", input) }
23 }
24 }
(备注:所有这些对我来说都是新鲜事,所以如果这完全是废话,请原谅。)
Iteratee相当愚蠢,它只读取所有的块,对接收到的字节数求和,并打印出一些消息。当我用一些数据调用控制器操作时,一切都按预期工作——我可以观察到迭代对象接收到所有块,当读取所有数据时,它切换到状态“完成”,请求结束
现在我开始研究代码,因为我想看看这两种情况下的行为:
- 在读取所有输入之前切换到状态错误
- 在读取所有输入之前切换到完成状态,并返回
结果,而不是
Int
17 case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Error else 'Cont, input = in, received = received + in.e.length)
因此,我只是添加了一个条件,如果接收到超过10000字节,则切换到错误状态。我得到的输出是:
'Cont Empty 0
'Cont El([B@38ecece6) 8192
'Error El([B@4ab50d3c) 16384
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
然后请求将永远挂起,永远不会结束。我对上述文档的期望是,当我调用迭代对象的fold
中的error
函数时,处理应该停止。这里发生的事情是,在调用error
之后,多次调用Iteratee的fold方法,然后请求挂起
当我在读取所有输入之前切换到done状态时,行为非常相似。将第15行更改为:
15 case 'Done => { println("Done with " + input); done(if (input == EOF) Right(received) else Left(BadRequest), Input.Empty) }
第17行至:
17 case in: El[Array[Byte]] => copy(state = if(received + in.e.length > 10000) 'Done else 'Cont, input = in, received = received + in.e.length)
生成以下输出:
'Cont Empty 0
'Cont El([B@16ce00a8) 8192
'Done El([B@2e8d214a) 16384
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
Done with El([B@2e8d214a)
请求再次永远挂起
我的主要问题是,为什么在上述情况下,这一请求被搁置。如果有人能说明这一点,我将不胜感激 您的理解完全正确,我刚刚向master推出了一个补丁: 修复了这两种情况以及迭代对象中的异常
在case类中使用copy进行迭代很好。Play 2.1的情况一定发生了变化-Promise不再是参数化的,并且这个示例不再编译。感谢您的修复和好话,我们将尽快尝试修复!