我想了解Play 2.0框架的反應式I/O概念。爲了從一開始就得到更好的理解,我決定跳過框架的幫助程序來構造不同種類的迭代,並從頭開始編寫自定義Iteratee
,供BodyParser
用於解析請求主體。爲什麼調用錯誤或在BodyParser的迭代器中完成請求在Play Framework 2.0中掛起?
與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([[email protected]) 8192
'Error El([[email protected]) 16384
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
Error
然後請求永遠掛起並永不結束。我從上面提到的文檔中獲得的期望是,當我調用Iteratee的fold
中的error
函數時,應該停止處理。這裏發生的事情是,在調用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([[email protected]) 8192
'Done El([[email protected]) 16384
Done with El([[email protected])
Done with El([[email protected])
Done with El([[email protected])
Done with El([[email protected])
,並再次請求永遠掛起。
我的主要問題是爲什麼請求掛在上面提到的情況。如果有人能說明這一點,我將不勝感激!
感謝您的修復和友好的話,將盡快修復! – lost 2012-07-14 22:31:47