-->

为什么叫使得错误或在BodyParser的Iteratee完成请求播放Framework 2.0的挂

2019-06-26 06:14发布

我想了解游戏2.0框架的反应式I / O的概念。 为了得到从一开始就更好地了解我决定跳过框架的助手来构建不同类型的iteratees和编写自定义Iteratee从头由使用BodyParser解析请求主体。

在现有的信息开始Iteratees和ScalaBodyParser文档和关于游戏的反应我两个报告/ 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是非常愚蠢的,它只是读取所有块,总结了接收的字节数,并打印出一些消息。 一切正常,当我打电话了一些数据控制器动作如预期 - 我可以观察到所有块由Iteratee接收,当所有数据被读取切换到状态完成,请求结束。

现在,我开始玩的代码,因为我想看到这两种情况下的行为:

  • 切换到状态错误读取所有输入之前。
  • 切换到所有输入之前完成状态被读取并返回一个Result ,而不是Int

我的上述文件的理解是,这两个应该是可能的,但实际上我不能够理解观察到的行为。 为了测试我改变线17上面的代码与所述第一种情况:

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

然后请求永远挂起,永远不会结束。 从上面提到的文档我的期望是,当我打电话的error里面函数fold的Iteratee的处理应该停止。 这到底是怎么发生的是,Iteratee的折叠方法被调用了几次后, error被称为-好,然后请求挂起。

当我阅读完所有输入之前切换到完成状态的行为颇为相似。 更改第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)

并再次要求永久挂起。

我的主要问题是,为什么请求被挂在上述案件。 如果任何人都可以在此阐明我将不胜感激!

Answer 1:

你的理解是完全正确的,我刚才推修复掌握:

https://github.com/playframework/Play20/commit/ef70e641d9114ff8225332bf18b4dd995bd39bcc

修正了在Iteratees这两种情况下加例外。

在案例类尼斯使用的副本BTW做一个Iteratee。



Answer 2:

事情必须与播放2.1已经改变 - 无极不再是参数,并且这个例子不再编译。



文章来源: Why makes calling error or done in a BodyParser's Iteratee the request hang in Play Framework 2.0?